关于android:TextWatcher的onTextChanged,beforeTextChanged和afterTextChanged之间的区别

Differences between TextWatcher 's onTextChanged, beforeTextChanged and afterTextChanged

在我的Android项目中,我必须将TextChangedListener(TextWatcher)添加到编辑文本视图。 它包括三个部分:

  • onTextChanged()
  • beforeTextChanged()
  • afterTextChanged()

这三个有什么区别? 我不得不在键侦听器上实现对表的搜索,对于我来说,这三个表看起来都一样。 它们的功能也相同。 当我输入一部分产品名称时,该表将仅使用其中包含输入文字的那些产品进行重绘。 但是我使用了afterTextChanged()部分。 我的代码是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
EditProduct.addTextChangedListener(new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence s, int start, int before,
                int count) {
            // TODO Auto-generated method stub

            // System.out.println("onTextChanged"+s);
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
            // TODO Auto-generated method stub
            // System.out.println("beforeTextChanged"+s);
        }

        @Override
        public void afterTextChanged(Editable s) {
            // TODO Auto-generated method stub
            // System.out.println("afterTextChanged"+s);

            String new_prx = s.toString();

            System.out.println(s);
            mini_productList = new ArrayList<Product>();

            // mini_productList
            int count = 0;
            if (new_prx.equals("")) {

                loadtableProducts(productList);

            } else {

                for (int i = 0; i < productList.size(); i++) {

                    if (productList.get(i).getDescription().toString()
                            .substring(0, (new_prx.length()))
                            .equalsIgnoreCase(new_prx)) {
                        mini_productList.add(productList.get(i));
                        count++;

                    }
                }

                loadtableProducts(mini_productList);
            }
        }
    });

那么有人可以给我解释这三个方面吗?


首先,很难理解beforeTextChangedonTextChanged的参数。在示例中查看它们可能会有所帮助。几次观看以下演示。注意计数。

  • 红色突出显示是即将被绿色文本替换的旧文本。
  • 绿色突出显示的是新文本,仅替换了红色文本。

enter image description here

beforeTextChanged

  • start是红色突出显示的文本(即将被删除)的起始索引
  • count是红色突出显示的文本的长度(即将被删除)
  • after是绿色突出显示的文本的长度(即将添加)

onTextChanged

  • start是绿色突出显示的文本(刚刚添加)的起始索引。
    这与beforeTextChangedstart相同。
  • before是红色突出显示的文本(刚删除的文本)的长度。
    这与beforeTextChangedcount相同。
  • count是绿色突出显示的文本(刚刚添加)的长度。
    这与beforeTextChangedafter相同。

afterTextChanged

  • editable是EditText中的可编辑文本。您可以在这里更改它。这样做将再次触发所有TextWatcher事件。
  • 您未获得有关更改内容的任何信息。如果您想知道,可以在onTextChanged中设置一个跨度,然后在此处查找该跨度。

什么时候使用?

如果要观察所做的更改,请使用beforeTextChanged()onTextChanged()。但是,您不能使用这两种方法之一来更改CharSequence文本。

如果要在更改后进一步修改文本,请在afterTextChanged()中进行操作。

如果您想自己玩,这里是代码。

MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class MainActivity extends AppCompatActivity {

    final static int RED_COLOR = Color.parseColor("#fb7373");
    final static int GREEN_COLOR = Color.parseColor("#40de83");

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        EditText editText = findViewById(R.id.editText);
        final TextView tvBeforeText = findViewById(R.id.tvBeforeText);
        final TextView tvBeforeNumbers = findViewById(R.id.tvBeforeNumbers);
        final TextView tvAfterText = findViewById(R.id.tvAfterText);
        final TextView tvAfterNumbers = findViewById(R.id.tvAfterNumbers);

        editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                SpannableString spannableString = new SpannableString(s);
                BackgroundColorSpan backgroundSpan = new BackgroundColorSpan(RED_COLOR);
                spannableString.setSpan(backgroundSpan, start, start + count, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                tvBeforeText.setText(spannableString);
                tvBeforeNumbers.setText("start=" + start +"  count=" + count +" after=" + after);
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                SpannableString spannableString = new SpannableString(s);
                BackgroundColorSpan backgroundSpan = new BackgroundColorSpan(GREEN_COLOR);
                spannableString.setSpan(backgroundSpan, start, start + count, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                tvAfterText.setText(spannableString);
                tvAfterNumbers.setText("start=" + start +" before=" + before +" count=" + count);
            }

            @Override
            public void afterTextChanged(Editable s) {
                Log.i("TAG","afterTextChanged:" + s);
            }
        });
    }
}

activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="5dp">

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:text="beforeTextChanged" />

    <TextView
        android:id="@+id/tvBeforeText"
        android:textSize="17sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/tvBeforeNumbers"
        android:textSize="17sp"
        android:text="start=0 count=0 after=0"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:layout_marginTop="20dp"
        android:text="onTextChanged" />

    <TextView
        android:id="@+id/tvAfterText"
        android:textSize="17sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/tvAfterNumbers"
        android:textSize="17sp"
        android:text="start=0 count=0 after=0"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

onTextChanged在文本更改期间运行。

afterTextChanged在更改文本后立即运行。

beforeTextChanged在更改文本之前立即运行。

根据您要分配变量或执行操作的时间,可能要在更改之前或之后运行代码。

这是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
String afterTextChanged ="";
String beforeTextChanged ="";
String onTextChanged ="";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    et = (EditText)findViewById(R.id.editText);

    et.addTextChangedListener(new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence s, int st, int b, int c)
        {
            onTextChanged = et.getText().toString();
        }

        @Override
        public void beforeTextChanged(CharSequence s, int st, int c, int a)
        {
            beforeTextChanged = et.getText().toString();
        }

        @Override
        public void afterTextChanged(Editable s)
        {
            afterTextChanged = et.getText().toString();
            Toast.makeText(Activity.this,"before:" + beforeTextChanged
                                           + '
' +"on:" + onTextChanged
                                           + '
' +"after:" + afterTextChanged
                           ,Toast.LENGTH_SHORT).show();
        }
    });
}

在这种情况下,假设您将文本从" h"更改为" hi",输出将是:

before:"h"
on:"hi"
after:"hi"


Android TextChangedListener是一种在输入字段的文本更改时调用的触发器。

TextChangedListener具有三个事件。

1.beforeTextChanged:这意味着字符将被一些新文本替换。文本不可编辑。当您需要查看将要更改的旧文本时,将使用此事件。

2.onTextChanged:已进行更改,某些字符刚刚被替换。文本不可编辑。当您需要查看文本中的哪些字符是新字符时,将使用此事件。

3.afterTextChanged:与上面相同,除了现在文本是可编辑的。当您需要查看并可能编辑新文本时,将使用此事件。


  • abstract void afterTextChanged(Editable s)

This method is called to notify you that, somewhere within s, the
text has been changed.

  • abstract void beforeTextChanged(CharSequence s, int start, int count,
    int after)

This method is called to notify you that, within s, the count
characters beginning at start are about to be replaced by new text
with length after.

  • abstract void onTextChanged(CharSequence s, int start, int before, int count)

This method is called to notify you that, within s, the count
characters beginning at start have just replaced old text that had
length before.

您可以在此处了解更多信息。


  • afterTextChanged (Editable s) - This method is called when the text has been changed. Because any changes you make will cause this
    method to be called again recursively, you have to be watchful about
    performing operations here, otherwise it might lead to infinite loop.

  • beforeTextChanged (CharSequence s, int start, int count, int after) - This method is called to notify you that, within s, the count
    characters beginning at start are about to be replaced by new text
    with length after. It is an error to attempt to make changes to s from
    this callback.

  • onTextChanged (CharSequence s, int start, int before, int count) - This method is called to notify you that, within s, the count
    characters beginning at start have just replaced old text that had
    length before. It is an error to attempt to make changes to s from
    this callback.