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

# 概要
プログラム中で初期化した [TextInputLayout](https://developer.android.com/reference/android/support/design/widget/TextInputLayout.html) の中身の EditText インスタンスを差し替えたい場合、どうするか、について述べます。

----

# [TextInputLayout](https://developer.android.com/reference/android/support/design/widget/TextInputLayout.html)
EditText を持つ Support Library の Layout です。マテリアルデザイン準拠のテキスト入力フォームを実装する際に役立ちます。 LinearLayout を継承して実装されているようです。

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

```xml
<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](https://developer.android.com/reference/android/support/design/widget/TextInputLayout.html#addView(android.view.View,%20int,%20android.view.ViewGroup.LayoutParams)) メソッドを使う
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 を渡す必要があります。

## コード例

```kotlin
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 を使って書けます。

```kotlin: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](https://developer.android.com/reference/android/support/design/widget/TextInputLayout.html) の中身の EditText インスタンスを差し替えたい場合、
引数3つの [TextInputLayout.addView](https://developer.android.com/reference/android/support/design/widget/TextInputLayout.html#addView(android.view.View,%20int,%20android.view.ViewGroup.LayoutParams)) メソッドを使いましょう。