7

我需要检测 EditText 中的文本更改。我已经尝试过 TextWatcher,但它并没有以我期望的方式工作。采取 onTextChanged 方法:

public void onTextChanged( CharSequence s, int start, int before, int count )

假设我已经在 EditText 中有文本“John”。如果按另一个键“e”,s将是“Johne”,start将是 0,before将是 4,count将是 5。我希望这种方法的工作方式将是 EditText 之前的内容和之前的内容之间的区别它即将成为。

所以我希望:

s = "Johne"
start = 4 // inserting character at index = 4
before = 0 // adding a character, so there was nothing there before
count = 1 // inserting one character

每次按下某个键时,我都需要能够检测到单个更改。因此,如果我有文本“John”,我需要知道在索引 4 处添加了“e”。如果我退格“e”,我需要知道从索引 4 中删除了“e”。如果我将光标放在“J”之后" 和退格,我需要知道 "J" 已从索引 0 中删除。如果我在 "J" 所在的位置放置 "G",我想知道 "G" 在索引 0 处替换了 "J"。

我怎样才能做到这一点?我想不出一个可靠的方法来做到这一点。

4

4 回答 4

12

使用 textwatcher 并自己做差异。将先前的文本存储在观察者中,然后将先前的文本与您在 onTextChanged 中获得的任何序列进行比较。由于 onTextChanged 在每个字符之后都会触发,因此您知道之前的文本和给定的文本最多会相差一个字母,这应该可以很容易地找出在哪里添加或删除了哪个字母。IE:

new TextWatcher(){ 
    String previousText = theEditText.getText();

    @Override 
    onTextChanged(CharSequence s, int start, int before, int count){
        compare(s, previousText); //compare and do whatever you need to do
        previousText = s;
    }

    ...
}
于 2012-02-27T03:54:00.257 回答
1

您可以遵循的最佳方法来识别文本更改。

var previousText = ""


override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
    previousText = s.toString()
}

override fun onTextChanged(newText: CharSequence?, start: Int, before: Int, count: Int) {

    val position = start + before ;

    if(newText!!.length > previousText.length){ //Character Added
        Log.i("Added Character", " ${newText[position]} ")
        Log.i("At Position", " $position ")
    } else {  //Character Removed
        Log.i("Removed Character", " ${previousText[position-1]} ")
        Log.i("From Position", " ${position-1} ")
    }
}

override fun afterTextChanged(finalText: Editable?) { }
于 2019-04-30T06:02:59.763 回答
0

每次更改文本时,您都需要存储和更新之前的 CharSequence。您可以通过实现TextWatcher来做到这一点。

例子:

final CharSequence[] previousText = {""};
editText.addTextChangedListener(new TextWatcher()
{
    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2)
    {
    }

    @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2)
    {
        if(i1 > 0)
        {
            System.out.println("Removed Chars Positions & Text:");
            for(int index = 0; index < i1; index++)
            {
                System.out.print((i + index) + " : " + previousText[0].charAt(i + index)+", ");
            }
        }
        if(i2 > 0)
        {
            System.out.println("Inserted Chars Positions & Text:");
            for(int index = 0; index < i2; index++)
            {
                System.out.print((index + i) + " : " + charSequence.charAt(i + index)+", ");
            }
            System.out.print("\n");
        }
        previousText[0] = charSequence.toString();//update reference
    }

    @Override public void afterTextChanged(Editable editable)
    {
    }
});
于 2017-03-26T17:21:29.483 回答
0

我最近遇到了完全相同的问题,我编写了自己的自定义算法来检测 TextWatcher 输出中的差异。

算法 -

我们存储 4 样东西——

  1. 旧选择大小
  2. 旧文本
  3. 光标/选择之前的旧文本序列。
  4. 光标/选择后的旧文本序列。

以上 4 件事在beforeTextChanged()回调期间更新。

现在在onTextChanged()回调期间,我们计算以下两件事 -

  1. 光标/选择之前的新文本序列。
  2. 光标/选择后的新文本序列。

现在可能出现以下情况 -

情况1

New text sequence before the cursor/selection == Old text sequence before the cursor/selectionNew text sequence after the cursor/selection isASuffixOf Old text sequence after the cursor/selection

这是一个删除转发案例。删除的字符数可以通过 oldText 长度减去 newText 长度来计算。

例子 -

旧文本 = Hello wo|rld(|代表光标)

光标/选择之前的旧文本序列 =Hello wo

光标/选择后的旧文本序列 =rld

旧选择大小 =0

新文本 = Hello wo|ld(|代表光标)

光标/选择之前的新文本序列 =Hello wo

光标/选择之后的新文本序列 =ld

显然,这是向前删除 1 个字符的情况。

案例2

New text sequence after the cursor/selection == Old text sequence after the cursor/selectionNew text sequence before the cursor/selection isAPrefixOf Old text sequence before the cursor/selection

这是一个向后删除的情况。删除的字符数可以通过 oldText 长度减去 newText 长度来计算。

例子 -

旧文本 = Hello wo|rld(|代表光标)

光标/选择之前的旧文本序列 =Hello wo

光标/选择后的旧文本序列 =rld

旧选择大小 =0

新文本 = Hello w|rld(|代表光标)

光标/选择之前的新文本序列 =Hello w

光标/选择之后的新文本序列 =rld

显然,这是向后删除 1 个字符的情况。

案例3

New text sequence after the cursor/selection == Old text sequence after the cursor/selectionOld text sequence before the cursor/selection isAPrefixOf New text sequence before the cursor/selection

这是一个插入盒。old text sequence from cursor + old text sequence after cursor可以通过从新文本字符串中删除 来计算确切的插入字符串。

例子 -

旧文本 = Hello wo|rld(|代表光标)

光标/选择之前的旧文本序列 =Hello wo

光标/选择后的旧文本序列 =rld

旧选择大小 =0

新文本 = Hello wo123|rld(|代表光标)

光标/选择之前的新文本序列 =Hello wo123

光标/选择之后的新文本序列 =rld

显然,这是插入的情况,插入的字符串是123

案例4

如果上述情况都不满足,那么我们可以说它是一个替换情况。并且替换数据已经由onTextChanged回调中的 TextWatcher 提供。

这是上述算法的代码 -


class MyTextWatcher : android.text.TextWatcher {

        var oldSelectionSize = 0
        var oldText: String = ""
        var oldSequenceBeforeCursor: String = ""
        var oldSequenceAfterCursor: String = ""

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {

            oldSelectionSize = editText.selectionEnd - editText.selectionStart
            oldText = s.toString()
            oldSequenceBeforeCursor = s?.subSequence(0, editText.selectionStart).toString()
            oldSequenceAfterCursor = s?.subSequence(editText.selectionEnd, s.length).toString()
        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {

            s?.toString()?.let { newText ->
                val newSequenceBeforeCursor = newText.subSequence(0, selectionStart).toString()
                val newSequenceAfterCursor = newText.subSequence(selectionEnd, newText.length)
                        .toString()

                if (newSequenceBeforeCursor == oldSequenceBeforeCursor &&
                        oldSequenceAfterCursor.endsWith(newSequenceAfterCursor))
                    // handle delete forward 
                    // number of characters to delete ==>
                    // if(oldSelectionSize > 0) then deleted number of characters = oldSelectionSize
                    // else number of characters to delete = oldText.length - newText.length
                else if (newSequenceAfterCursor == oldSequenceAfterCursor &&
                        oldSequenceBeforeCursor.startsWith(newSequenceBeforeCursor))
                    // handle delete backward 
                    // number of characters to delete ==>
                    // if(oldSelectionSize > 0) then deleted number of characters = oldSelectionSize
                    // else number of characters to delete = oldText.length - newText.length
                else if (newSequenceAfterCursor == oldSequenceAfterCursor &&
                        newSequenceBeforeCursor.startsWith(oldSequenceBeforeCursor))
                    // handle insert
                    // inserted string = (newText - oldSequenceBeforeCursor) - oldSequenceAfterCursor
                else
                    // handle replace
                    // replace info already provided in `onTextChanged()` arguments.
            }
        }

        override fun afterTextChanged(s: Editable?) {
        }
    }

于 2021-09-13T22:29:33.700 回答