7

EditText でテキストの変更を検出する必要があります。TextWatcher を試してみましたが、期待どおりに動作しません。onTextChanged メソッドを使用します。

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

EditText に既に "John" というテキストがあるとします。別のキーを押すと、「e」、s「Johne」 、0、4、5startbeforeなりcountます。このメソッドが機能すると予想される方法は、以前の 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」がある場合、「e」がインデックス 4 に追加されたことを知る必要があります。「e」をバックスペースすると、インデックス 4 から「e」が削除されたことを知る必要があります。「J の後にカーソルを置くと、 "とバックスペースを使用すると、"J" がインデックス 0 から削除されたことを知る必要があります。"J" があった場所に "G" を配置すると、"G" がインデックス 0 の "J" に置き換わったことを知りたいのです。

どうすればこれを達成できますか?これを行うための信頼できる方法は考えられません。

4

4 に答える 4

12

textwatcher を使用して、自分で diff を実行してください。前のテキストをウォッチャー内に保存し、前のテキストを onTextChanged で取得したシーケンスと比較します。onTextChanged はすべての文字の後に発生するため、前のテキストと指定されたテキストの違いは最大で 1 文字であることがわかります。これにより、どの文字がどこで追加または削除されたかを簡単に把握できるはずです。すなわち:

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 に答える
0

私は最近まったく同じ問題に直面し、TextWatcher の出力から差分を検出する独自のカスタム アルゴリズムを作成しました。

アルゴリズム -

私たちは4つのものを保管します -

  1. 古い選択サイズ
  2. 古いテキスト
  3. カーソル/選択の前の古いテキスト シーケンス。
  4. カーソル/選択の後の古いテキスト シーケンス。

beforeTextChanged()上記の 4 つのことは、コールバック中に更新されます。

コールバック中に、onTextChanged()次の 2 つのことを計算します -

  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

上記のケースのいずれも満たされない場合、それは交換ケースであると言えます。また、置き換えデータは、コールバックで TextWatcher によって既に提供されていonTextChangedます。

上記のアルゴリズムのコードは次のとおりです-


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 に答える