TextInputLayoutでテキストフィールド実装


まずは動作確認

↓な感じのテキストフィールドの実装方法を紹介します

実装方法

TextInputLayoutを使う

このいい感じなテキストフィールドを実現するためには、Design Support LibraryのTextInputLayoutを使います。

activity_main.xml
        <android.support.design.widget.TextInputLayout
            android:id="@+id/userNameTextImaputLayout"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_margin="16dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:errorEnabled="true"
            app:counterEnabled="true"
            app:counterMaxLength="10"
            app:hintEnabled="true"
            app:hintAnimationEnabled="true"
            android:layout_marginTop="67dp">

        </android.support.design.widget.TextInputLayout>

app:hintAnimationEnabled="true" でplaceholderのアニメーションを有効化しています。このアニメーションはマテリアルデザインに則っているため、自分でカスタマイズする必要なく、マテリアルデザインなアニメーションを実現できます。
ちなみにfalseにするとアニメーションしなくなります。
他にもapp: counterEnabled ="true"で右下の文字数カウンター表示を有効化しています。

子ViewにTextInputEditTextを配置

次に実際に入力するためのView、TextInputEditTextをTextInputLayoutの中にを入れます。

activity_main.xml
        <android.support.design.widget.TextInputLayout
            android:id="@+id/userNameTextImaputLayout"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_margin="16dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:errorEnabled="true"
            app:counterEnabled="true"
            app:counterMaxLength="10"
            app:hintEnabled="true"
            app:hintAnimationEnabled="true"
            android:layout_marginTop="67dp">

            <android.support.design.widget.TextInputEditText
                android:id="@+id/userNameEditText"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="ユーザー名"
                android:imeOptions="actionSend"
                android:inputType="text"
                android:maxLines="1"
                android:textSize="20sp"/>

        </android.support.design.widget.TextInputLayout>

縦画面のみ対応の場合、子Viewは普通のEditTextでも大丈夫なのですが、横画面にした時にバグがあるため、横も対応する場合は TextInputEditText を指定します。

以上でいい感じのテキストフィールドが実現できます。
エラー文の表示もしたい場合はコードでやることになります。

エラー文表示

MainActivity.kt
        binding.userNameEditText.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(s: Editable?) {}
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                if (s!!.length > binding.userNameTextImaputLayout.counterMaxLength) {
                    binding.userNameTextImaputLayout.error = "ユーザー名は10文字以内で入力してください"
                } else {
                    binding.userNameTextImaputLayout.error = null
                }
            }
        })

TextInputEditTextの入力イベントをTextWatcherで監視し、最大文字数を超えたらTextInputLayoutのerrorにエラー文を設定します。最大文字数を超えていなければerrorにnullを設定し、エラー文字を消します。
この最大文字数を超えたら判定は自分で行うことになります。
if (s!!.length > binding.userNameTextImaputLayout.counterMaxLength) {
この部分ですね。

これでエラー文の表示もできるようになりました。

最後に

簡単にいい感じのテキストフィールドを実装することができました。
こんな感じのテキストフィールドを欲しくなることがあると思うので、そんな時は自作するのではなく、これ使うと良いと思います

コードはこちらあります

※ちなみに...
親のレイアウトにConstraintLayoutを使っています
Databindingを使用しています
コードはkotlinで書いています