Android
EditText

プログラムで生成した TextInputLayout に EditText をセットする

概要

プログラム中で初期化した TextInputLayout の中身の EditText インスタンスを差し替えたい場合、どうするか、について述べます。


TextInputLayout

EditText を持つ Support Library の Layout です。マテリアルデザイン準拠のテキスト入力フォームを実装する際に役立ちます。 LinearLayout を継承して実装されているようです。

レイアウトファイルで定義する場合

通常はレイアウトファイルで EditText を囲むように定義します。

<android.support.design.widget.TextInputLayout
    android:id="@+id/input_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <EditText
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:maxLines="1"
        android:inputType="text"
        android:imeOptions="actionSearch"
        />
</android.support.design.widget.TextInputLayout>

プログラム中で初期化する場合

一方、プログラム中でこのクラスのインスタンスを生成すると、editText のインスタンスが null の状態になっているので、EditText のインスタンスを別途差し込む必要があります。setEditText というメソッドはあるのですが、 private メソッドなので呼び出すことはできません。


では、どうするか?

TextInputLayout.addView メソッドを使う

index と LinearLayout.LayoutParams を指定した addView メソッドだと、TextInputLayout で定義されているメソッドが呼ばれるようです。このメソッドだと EditText インスタンスの入れ替えをやってくれます。

https://github.com/aosp-mirror/platform_frameworks_support/blob/android-cts-8.0_r1/design/src/android/support/design/widget/TextInputLayout.java#L269-L283

なお、このメソッドの第3引数は型が ViewGroup.LayoutParams ですが、それを渡すと内部で ClassCastException が発生します。

Caused by: java.lang.ClassCastException: android.view.ViewGroup$LayoutParams cannot be cast to android.widget.LinearLayout$LayoutParams
   at android.support.design.widget.TextInputLayout.updateInputLayoutMargins(TextInputLayout.java:411)
   at android.support.design.widget.TextInputLayout.addView(TextInputLayout.java:281)

https://github.com/aosp-mirror/platform_frameworks_support/blob/android-cts-8.0_r1/design/src/android/support/design/widget/TextInputLayout.java#L411

TextInputLayout が LinearLayout のサブクラスなので当然といえばそうなります。このため、第3引数には LinearLayout.LayoutParams を渡す必要があります。

コード例

val inputLayout = TextInputLayout(context)
val editText = EditText(context)

// 以下、任意の設定
editText.maxLines   = 1
editText.inputType  = InputType.TYPE_CLASS_TEXT
editText.imeOptions = EditorInfo.IME_ACTION_SEARCH

// TextInputLayout.addView を使う
inputLayout.addView(
    editText, 
    0, 
    LinearLayout.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.WRAP_CONTENT
    )
)

なお、Kotlin なら apply を使って書けます。

apply
TextInputLayout(context)
    .apply {
        addView(
            EditText(context).apply {
                    maxLines   = 1
                    inputType  = InputType.TYPE_CLASS_TEXT
                    imeOptions = EditorInfo.IME_ACTION_SEARCH
            },
            0,
            LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT
            )
        )
    }

まとめ

プログラム中で初期化した TextInputLayout の中身の EditText インスタンスを差し替えたい場合、
引数3つの TextInputLayout.addView メソッドを使いましょう。