Подтвердить что ты не робот

Обнаруживать, было ли изменено содержимое EditText пользователем или программно?

Мне нужен способ определить, был ли изменен EditText пользователем, который набрал что-то или приложение изменило текст программно. Любой стандартный способ сделать это? Думаю, я всегда мог бы что-то взломать, как отменить TextWatcher до setText() и снова установить его обратно, но должен быть лучший способ сделать это... правильно?

Я попытался проверить, сфокусировано ли EditText в TextWatcher, но это мало помогло, так как EditTexts фокусируется "полуслучайно" в любом случае при прокрутке...

 

Фон

У меня есть ListView с EditTexts в каждом элементе listitem. Я проанализировал основную проблему хранения значений для EditTexts для повторного использования при прокрутке пользователя.

У меня также есть TextWatcher, который суммирует значения во всех EditTexts и отображает сумму, когда пользователь редактирует содержимое любого из EditTexts.

Проблема заключается в том, что когда я прокручиваю список, и мой пользовательский адаптер повторно вводит сохраненные значения в EditTexts на bindView(), что также вызывает метод TextWatchers afterTextChanged(), что приводит к задержке прокрутки, срабатывает функция "вверх".

4b9b3361

Ответ 1

Это отсортировалось давно, но для тех, кто находит здесь свой путь для поиска ответа, вот что я сделал:

Я закончил настройку тега EditText на какое-то произвольное значение прямо перед тем, как я собираюсь изменить его программно, и изменив значение, а затем сбросив значение тега до нуля. Затем в моем методе TextWatcher.afterTextChanged() я проверяю, является ли тег нулевым или не определяет, был ли это пользователь или программа, которые изменили значение. Работает как шарм!

Что-то вроде этого:

edit.setTag( "arbitrary value" );
edit.setText( "My Text Value" );
edit.setTag(null);

а затем

public void afterTextChanged(Editable s) {
    if( view.getTag() == null )             
        // Value changed by user
    else
        // Value changed by program
}

Ответ 2

Принятый ответ совершенно верен, но у меня есть другой подход;

@Override
public void onTextChanged(CharSequence charSequence, 
                         int start, int before, int count) {
    boolean userChange = Math.abs(count - before) == 1; 
    if (userChange) { 

    }
}

Это работает, проверяя, было ли изменение одним символом. Это не безупречное решение, поскольку операции копирования и вставки могут быть пропущены, а также несобственные изменения одного символа также будут пропущены. В зависимости от вашего варианта использования это может быть жизнеспособным решением.

Ответ 3

Одна вещь, которая мне помогала, - иметь поле boolean canListenInput. Используйте его внутри наблюдателя.

    email.addTextChangedListener(new TextWatcher() {
        @Override
        public void afterTextChanged(Editable s) {
            if (canListenInput) {
                emailChanged = true;
            }
        }
    });

Очистить его перед программным изменением текста. Установите его внутри восстановления onAttachedToWindow (после состояния):

@Override
public void onAttachedToWindow() {
    super.onAttachedToWindow();
    canListenInput = true;
}

Ответ 4

Вы можете сделать это, добавив:

private String current = "";
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(!s.toString().equals(current)){
   [your_edittext].removeTextChangedListener(this);

   //Format your string here...

   current = formatted;
   [your_edittext].setText(formatted);
   [your_edittext].setSelection(formatted.length());

   [your_edittext].addTextChangedListener(this);
}