Android: TextWatcher
による編集可能なEditText

AndroidでTextWatcher
による編集可能なEditText
の実装方法を整理する。
導入
Androidの開発で,テキストの入力欄のUIウィジェットにEditText
がある。このEditText
はデータの入力UIとして重宝するのだが,これがまた癖がある。
例えば,素の状態であれば入力した内容をそのままデータとして流用できない。別のButton
などのUIを用意し,そちらの選択時に処理する必要がある。
表示領域の都合などで,処理用のボタンを設置したくない場合がよくある。例えば,EditText
を使ったTextEditor
を作る場合なども困る。
TextWatcher
を使うことで入力した内容をそのままデータとして活用できる。そこで,TextWatcher
による編集可能なEditText
の実装方法を整理する。方法
EditText
の公式リファレンス (EditText | Android Developers) に,以下のようにEditText
への入力中の処理の実装方法が書かれている。
You also can receive callbacks as a user changes text by adding aTextWatcher
to the edit text. This is useful when you want to add auto-save functionality as changes are made, or validate the format of user input, for example. You add a text watcher using theTextView#addTextChangedListener
method.
TextWatcher
をEditText
に追加することで,ユーザーによるテキストの変更を,コールバックで受け取ることができる。TextView#addTextChangedListener
メソッドの引数に,TextWatcher
の実装を追加することで実現する。
TextWatcher
はEditText
に入力中の内容を監視するインターフェイスとなっている。テキストの入力時に呼ばれるコールバックは,TextWatcherのリファレンスに記載されており,タイミングに応じて以下の3の抽象メソッドが用意されている。
メソッド | 説明 |
---|---|
abstract void afterTextChanged(Editable s) | テキストの変更後に呼ばれる。 |
abstract void beforeTextChanged(CharSequence s, int start, int count, int after) | テキストの置換前に呼ばれる。start : 先頭からの位置count : 変更前の選択文字数after : 変更後の選択文字数 |
abstract void onTextChanged(CharSequence s, int start, int before, int count) | テキストの置換後に呼ばれる。start : 先頭からの位置before : 変更前の選択文字数count : 変更後の選択文字数 |
beforeTextChanged
は入力の反映前に呼ばれる。onTextChanged
は入力の反映後に呼ばれる。onTextChange
dとafterTextChanged
はタイミングが似ている。
テキストの入力直前に何か処理を行いたい場合,beforeTextChanged
のタイミングでやる。入力直後のタイミングであれば,onTextChanged
とafterTextChanged
のどちらでもいい。afterTextChanged
の中で文字を追加すると,また
afterTextChanged
が呼ばれる。このタイミングを検知する場合に,onTextChanged
が必要になる。それ以外は
afterTextChanged
でいいだろう。
仮引数に同じ変数名のcount
が使われているが,意味が違うことに注意する。
引数の並び順が,入力欄の先頭からの位置 (start
),変更前の選択文字数 (count/before
),変更後の選択文字数 (after/count
) の順番に並んでいると理解すると覚えやすいかもしれない。
例えば,2文字選択して1文字入力する場合count
, after
, before
はそれぞれ以下となる。
beforeTextChanged
:count
=2,after
=1onTextChanged
:before
=2,count
=1
入力直後に何か処理を行いたい場合がほとんどなので,基本的にafterTextChanged
のみ処理を実装することになるだろう。その場合,beforeTextChanged
とonTextChanged
の中身は空となる。
implements TextWatcher
を記入し,オーバーライドする。サンプル
EditText
の内容をTextView
に表示する簡単なサンプルを以下に掲載する。GitHub上にも公開している。
なお,Android 3.5.3で確認した。
package jp.senooken.android.edittextwithtextwatcher;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EditText et = findViewById(R.id.editText);
et.addTextChangedListener(new MyTextWatcher());
}
private class MyTextWatcher implements TextWatcher {
private final TextView afterTextChanged_ = findViewById(R.id.afterTextChanged);
private final TextView beforeTextChanged_ = findViewById(R.id.beforeTextChanged);
private final TextView onTextChanged_ = findViewById(R.id.onTextChanged);
@Override
public void afterTextChanged(Editable s) {
String input= s.toString();
afterTextChanged_.setText(input);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
String input= "start=" + start
+ ", count=" + count
+ ", after=" + after
+ ", s=" + s.toString();
beforeTextChanged_.setText(input);
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
String input= "start=" + start
+ ", before=" + before
+ ", count=" + count
+ ", s=" + s.toString();
onTextChanged_.setText(input);
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<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:orientation="vertical"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/afterTextChanged" />
<TextView
android:id="@+id/afterTextChanged"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/beforeTextChanged" />
<TextView
android:id="@+id/beforeTextChanged"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/onTextChanged" />
<TextView
android:id="@+id/onTextChanged"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autofillHints="number"
android:ems="10"
android:inputType="number"
android:hint="@string/hint"
tools:targetApi="o" />
</LinearLayout>
<resources>
<string name="app_name">EditTextWithTextWatcher</string>
<string name="hint">Fill this.</string>
<string name="afterTextChanged">afterTextChanged: </string>
<string name="beforeTextChanged">beforeTextChanged: </string>
<string name="onTextChanged">onTextChanged: </string>
</resources>
EditText
に入力した内容を3の抽象メソッドに対応したTextView
に引数と共に表示させている。
これで,beforeTextChanged
とonTextChanged
の引数の意味について理解できる。
結論
EditText
に入力された内容をTextWatcher
で処理する方法を整理した。
EditText
を扱う上でほぼ必須の処理なので,整理できてよかった。地味に,公式リファレンスのbeforeTextChanged
とonTextChanged
の引数の意味がわかりにくくて,これの意味を理解するのに時間がかかった。
やはり自分で簡単な動作するサンプルを作成してみるのが,手間はかかるものの効果的だと感じた。
今後も,サンプルを作りながら理解を深めていきたい。
“Android:
TextWatcher
による編集可能なEditText
” に対して1件のコメントがあります。