TextInputLayoutでエラーメッセージの表示/非表示を無理矢理出してみた
TextInputLayout | Android Developers
TextInputLayout
というものワクテカするものがあるらしく書いてみましたが、
ちょっと残念な感じの事態に遭遇して、やや残念な感じに対処してみた記録です。
内容
- とりあえず置いてみた
- エラーメッセージを表示する
- 2回目以降表示のバグがある
- エラーメッセージのViewを手動で追加してみる
とりあえず置いてみた
一番単純な形で置いてみました。InputTextLayoutの中にEditTextを置く必要があるっぽいです。
あと、
compile 'com.android.support:design:23.1.0'
が必要です。念のため。
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:orientation="vertical" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <TextView android:text="TextInputLayoutTest" android:textSize="30sp" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <android.support.design.widget.TextInputLayout android:layout_width="200dp" android:layout_height="wrap_content" > <EditText android:id="@+id/userid" android:textSize="20sp" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="ユーザIDを入力"/> </android.support.design.widget.TextInputLayout> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="フォーカス外し用" /> </LinearLayout>
これだけでも動いて楽しい。
エラーメッセージを表示する
バリデーションに失敗した場合など、setError(CharSequence error)
メソッドでエラーメッセージが表示できるそうです。
ボタンを押したとき、EditText
の値が空白だったら空白ですよ、と表示させてみます。
// 追加部分のみ mTextInputLayout = (TextInputLayout) findViewById(R.id.text_input_layout); Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(mTextInputLayout.getEditText().getText().length() == 0) { mTextInputLayout.setErrorEnabled(true); mTextInputLayout.setError("空白です"); } else { mTextInputLayout.setErrorEnabled(false); mTextInputLayout.setError(null); } } });
<!-- 一部省略 --> <android.support.design.widget.TextInputLayout android:id="@+id/text_input_layout" android:layout_width="200dp" android:layout_height="wrap_content" > <EditText android:id="@+id/userid" android:textSize="20sp" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="ユーザIDを入力"/> </android.support.design.widget.TextInputLayout> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="フォーカス外し用" /> <Button android:id="@+id/button" android:layout_height="wrap_content" android:layout_width="wrap_content" android:textSize="30sp" android:text="Push!" />
一見動いているように見えるのですが...
もうちょっとがちゃがちゃやって、2回目以降のバリデーションに失敗した場合...
エラーメッセージが出て来ないじゃないですか。
ここの問題の処理は下記なのですが、なんでおかしいのか、 手動でErrorViewの追加とか試してみたけど、あまり上手くも行かず..。
public void setErrorEnabled(boolean enabled) { if (mErrorEnabled != enabled) { if (mErrorView != null) { ViewCompat.animate(mErrorView).cancel(); } if (enabled) { mErrorView = new TextView(getContext()); mErrorView.setTextAppearance(getContext(), mErrorTextAppearance); mErrorView.setVisibility(INVISIBLE); addView(mErrorView); if (mEditText != null) { // Add some start/end padding to the error so that it matches the EditText ViewCompat.setPaddingRelative(mErrorView, ViewCompat.getPaddingStart(mEditText), 0, ViewCompat.getPaddingEnd(mEditText), mEditText.getPaddingBottom()); } } else { removeView(mErrorView); mErrorView = null; } mErrorEnabled = enabled; } }
エラーメッセージのViewを手動で追加してみる
ライブラリのViewが表示されないと悲しいので、何とか自分でも考えてみました。
ErrorEnabledをさわらなければよい、というのはあるのですが、Errorのsetterでどうしても触れてしまいます。
public void setError(@Nullable CharSequence error) { if (!mErrorEnabled) { if (TextUtils.isEmpty(error)) { // If error isn't enabled, and the error is empty, just return return; } // Else, we'll assume that they want to enable the error functionality setErrorEnabled(true); // やーん }
もちろん、エラーメッセージが出る、出ないなら、ある程度は空白があるものとして、スペースができることを許容する、というのはありです。
ですが、あの、setErrorEnabled
でセットしてくれる、フォームの下線のスタイル使えないかな、とか、考えた結果、
- ユーザーに見せる前に、エラーメッセージのフォームがもう表示されないよう一回ON/OFFする
- TextInputLayoutの子要素に空のLinearLayoutかRelativeLayoutを追加
- エラーメッセージの欄は手動で上記の空のLayout要素に追加/削除する
- 空のレイアウト要素なのはViewの削除指定を分かりやすくするためでそれ以外の意味は無いです
という方針で実装してみました。コードは綺麗になりませんでしたが...。
利点としては、エラーメッセージがTextViewとして追加できるので、スタイルの指定が自分のような初心者に取ってやりやすいことですかね...*1。
public class MainActivity extends AppCompatActivity { private TextInputLayout mTextInputLayout; private LinearLayout mErrorMessagWrapper; private TextView mErrorMessage; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextInputLayout = (TextInputLayout) findViewById(R.id.text_input_layout); mTextInputLayout.setError("dummy"); mTextInputLayout.setErrorEnabled(false); mErrorMessagWrapper = (LinearLayout) findViewById(R.id.errorMessagWrapper); mErrorMessage = new TextView(this); mErrorMessage.setText("空白です"); Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(mTextInputLayout.getEditText().getText().length() == 0) { mTextInputLayout.setErrorEnabled(true); mTextInputLayout.setError("dummy"); mErrorMessagWrapper.addView(mErrorMessage); } else { mTextInputLayout.setErrorEnabled(false); mErrorMessagWrapper.removeView(mErrorMessage); } } }); }
<!-- TextInputLayout以外変更なし --> <android.support.design.widget.TextInputLayout android:id="@+id/text_input_layout" android:layout_width="200dp" android:layout_height="wrap_content" > <EditText android:id="@+id/userid" android:textSize="20sp" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="ユーザIDを入力"/> <LinearLayout android:orientation="horizontal" android:id="@+id/errorMessagWrapper" android:layout_width="match_parent" android:layout_height="wrap_content" /> </android.support.design.widget.TextInputLayout>
動作は下記のような感じです。
次のバージョンでサポートライブラリのバグ直すとかの話が見えた気がするので、早くバージョンアップしてほしい...。
*1:今回はしてないが! アニメーション等は書けばなんとかなる...?