今回のエンジニアブログを担当する佐藤です。
前回FAB(Floating Action Button)に引き続き、TextInputLayoutをつかったFloating Labels for EditTextを実装したいと思います。
【Floating Labels for EditText】
Floating Labels for EditTextは、TextInputLayoutを使用したMaterial DesignのTextEditです。
TextInputLayoutはDesign Support Libraryに追加された機能です。
TextInputLayoutを使用すると、入力フォーム選択時にラベルがフォームの上へ移動するアニメーションをするようになります。
実装はとても簡単でした。
今回もDesign Support Library使用するので、build.gradleに追記していきます。
build.gradle
dependencies { compile 'com.android.support:design:22.2.0' }
レイアウトは以下のようになっています。
activity_main.xml
<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:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" android:orientation="vertical" tools:context=".MainActivity"> <android.support.design.widget.TextInputLayout android:id="@+id/input_name" android:layout_width="match_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/name" android:layout_width="match_parent" android:layout_height="wrap_content" android:singleLine="true" android:hint="@string/name" /> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout android:id="@+id/input_password" android:layout_width="match_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/password" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textPassword" android:hint="@string/password" /> </android.support.design.widget.TextInputLayout> </LinearLayout>
string.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">FloationgLabelTextEdit</string> <string name="name">名前</string> <string name="password">パスワード</string> </resources>
android:hintで設定した文字が入力フォームに表示されています。
また、TextInputLayoutはsetError()でエラーメッセージを表示することができます。
MainActivity.java
public class MainActivity extends Activity{ TextInputLayout inputLayoutName; TextInputLayout inputLayoutPassword; EditText textName; EditText textPassword; Button btnOk; HashMap<String, Boolean> errorCheck; // パスワードの最小文字数 final int PASS_MIN = 6; // パスワードの最大文字数 final int PASS_MAX = 12; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); errorCheck = new HashMap<String, Boolean>(); errorCheck.put("name", false); errorCheck.put("password", false); inputLayoutName = (TextInputLayout) findViewById(R.id.input_name); inputLayoutPassword = (TextInputLayout) findViewById(R.id.input_password); textName = (EditText) findViewById(R.id.name); textPassword = (EditText) findViewById(R.id.password); // 入力中のチェック textName.addTextChangedListener(new EditTextWatcher(textName)); textPassword.addTextChangedListener(new EditTextWatcher(textPassword)); btnOk = (Button) findViewById(R.id.btn_ok); btnOk.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 名前の入力とパスワードの入力に不備がなければToastを表示 if(checkNameInput() || checkPassInput()) { Toast.makeText(view.getContext(), view.getContext().getText(R.string.input_success), Toast.LENGTH_SHORT).show(); }else{ updateButton(); } } }); } /** * 「名前」の入力チェック */ private boolean checkNameInput(){ // 空白ならエラー表示 if(textName.getText().toString().trim().isEmpty()){ inputLayoutName.setError(getString(R.string.error_name_empty)); return false; } inputLayoutName.setErrorEnabled(false); return true; } /** * 「パスワード」の入力チェック */ private boolean checkPassInput(){ String password = textPassword.getText().toString().trim(); // 空白ならエラー表示 if(password.length() == 0){ inputLayoutPassword.setError(getString(R.string.error_pass_empty)); return false; } // 最小文字数以下ならエラー表示 if(password.length() < PASS_MIN){ inputLayoutPassword.setError(getString(R.string.error_pass_min, PASS_MIN)); return false; } // 最大文字数を超えていたらエラー if(password.length() > PASS_MAX){ inputLayoutPassword.setError(getString(R.string.error_pass_max, PASS_MAX)); return false; } inputLayoutPassword.setErrorEnabled(false); return true; } /** * OKボタンの状態を更新 */ private void updateButton(){ // 入力内容に不備があれば押せないようにする if(!errorCheck.get("name") || !errorCheck.get("password")){ btnOk.setEnabled(false); }else{ btnOk.setEnabled(true); } } /** * 入力フォームの状態を取得する */ private class EditTextWatcher implements TextWatcher { View v; public EditTextWatcher(EditText editText) { v = editText; } @Override public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { } @Override public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { } @Override public void afterTextChanged(Editable editable) { // 文字を入力時に入力内容をチェックしエラーの表示やボタンの状態を更新する switch (v.getId()) { case R.id.name: errorCheck.put("name", checkNameInput()); break; case R.id.password: errorCheck.put("password", checkPassInput()); break; } updateButton(); } } }
実機で確認するとこうなりました!
動きが細かいですが、このような細かい動きでもMaterialDesignらしいアプリケーションになるので積極的に実装していきたいです!