Обнаруживать, было ли изменено содержимое EditText пользователем или программно?
Мне нужен способ определить, был ли изменен EditText пользователем, который набрал что-то или приложение изменило текст программно. Любой стандартный способ сделать это? Думаю, я всегда мог бы что-то взломать, как отменить TextWatcher до setText()
и снова установить его обратно, но должен быть лучший способ сделать это... правильно?
Я попытался проверить, сфокусировано ли EditText в TextWatcher, но это мало помогло, так как EditTexts фокусируется "полуслучайно" в любом случае при прокрутке...
Фон
У меня есть ListView с EditTexts в каждом элементе listitem. Я проанализировал основную проблему хранения значений для EditTexts для повторного использования при прокрутке пользователя.
У меня также есть TextWatcher, который суммирует значения во всех EditTexts и отображает сумму, когда пользователь редактирует содержимое любого из EditTexts.
Проблема заключается в том, что когда я прокручиваю список, и мой пользовательский адаптер повторно вводит сохраненные значения в EditTexts на bindView()
, что также вызывает метод TextWatchers afterTextChanged()
, что приводит к задержке прокрутки, срабатывает функция "вверх".
Ответы
Ответ 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);
}