Андроид на прослушивателе изменения текста

У меня ситуация, когда есть два поля. field1 и field2. Все что я хочу do - пустой field2 при изменении field1 и наоборот. Так что в конце только в одном поле есть содержимое.

field1 = (EditText)findViewById(R.id.field1);
field2 = (EditText)findViewById(R.id.field2);

field1.addTextChangedListener(new TextWatcher() {

   public void afterTextChanged(Editable s) {}

   public void beforeTextChanged(CharSequence s, int start,
     int count, int after) {
   }

   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
      field2.setText("");
   }
  });

field2.addTextChangedListener(new TextWatcher() {

   public void afterTextChanged(Editable s) {}

   public void beforeTextChanged(CharSequence s, int start,
     int count, int after) {
   }

   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
     field1.setText("");
   }
  });

Работает нормально, если я присоединяю addTextChangedListener только к field1, но когда Я делаю это для обоих полей приложение вылетает. Очевидно, потому что они пытаются изменить друг друга до бесконечности. Как только field1 изменяется, он очищает field2 в этот момент field2 изменен, поэтому он очистит field1 и так далее...

Может кто-нибудь предложить какое-нибудь решение?

Ответ 1

Вы можете добавить чек только для очистки, когда текст в поле не пустой (т.е. когда длина отличается от 0).

field1.addTextChangedListener(new TextWatcher() {

   @Override
   public void afterTextChanged(Editable s) {}

   @Override    
   public void beforeTextChanged(CharSequence s, int start,
     int count, int after) {
   }

   @Override    
   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
      if(s.length() != 0)
        field2.setText("");
   }
  });

field2.addTextChangedListener(new TextWatcher() {

   @Override
   public void afterTextChanged(Editable s) {}

   @Override
   public void beforeTextChanged(CharSequence s, int start,
     int count, int after) {
   }

   @Override
   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
      if(s.length() != 0)
         field1.setText("");
   }
  });

Документация для TextWatcher здесь.

Также соблюдайте правила именования.

Ответ 2

Я знаю, что это уже давно, но кто-то может когда-нибудь столкнуться с этим.

У меня была аналогичная проблема, в которой я бы назвал setText на EditText, и onTextChanged будет вызываться, когда я этого не хочу. Моим первым решением было написать некоторый код после вызова setText(), чтобы отменить урон, причиненный слушателем. Но это было не очень элегантно. После выполнения некоторых исследований и тестирования я обнаружил, что использование getText(). Clear() очищает текст почти так же, как setText ( "), но поскольку он не устанавливает текст, слушатель не вызывается, так что решил мою проблему. Я переключил все свои вызовы setText (" ") на getText(). Clear(), и мне больше не нужны бинты, так что, возможно, это тоже решит вашу проблему.

Попробуйте следующее:

Field1 = (EditText)findViewById(R.id.field1);
Field2 = (EditText)findViewById(R.id.field2);

Field1.addTextChangedListener(new TextWatcher() {

   public void afterTextChanged(Editable s) {}

   public void beforeTextChanged(CharSequence s, int start,
     int count, int after) {
   }

   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
      Field2.getText().clear();
   }
  });

Field2.addTextChangedListener(new TextWatcher() {

   public void afterTextChanged(Editable s) {}

   public void beforeTextChanged(CharSequence s, int start,
     int count, int after) {
   }

   public void onTextChanged(CharSequence s, int start,
     int before, int count) {
     Field1.getText().clear();
   }
  });

Ответ 3

Если вы используете Kotlin для разработки под Android, вы можете добавить TextChangedListener(), используя этот код:

myTextField.addTextChangedListener(object : TextWatcher{
        override fun afterTextChanged(s: Editable?) {}

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

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

Ответ 4

Я также столкнулся с той же проблемой и продолжаю получать полные исключения для стека, и я пришел со следующим решением.

    edt_amnt_sent.addTextChangedListener(new TextWatcher() {    
        @Override
        public void afterTextChanged(Editable s) {

            if (skipOnChange)
                return;

            skipOnChange = true;
            try {
                //method
                }
            } catch (NumberFormatException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                skipOnChange = false;
            }
        }
    });

    edt_amnt_receive.addTextChangedListener(new TextWatcher() {


        @Override
        public void afterTextChanged(Editable s) {

            if (skipOnChange)
                return;

            skipOnChange = true;
            try 
            {
                //method
            } catch (NumberFormatException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                skipOnChange = false;
            }
        }
    });

объявлено первоначально boolean skipOnChange = false;

Ответ 5

Немного поздно ответа, но вот многоразовое решение:

/**
 * An extension of TextWatcher which stops further callbacks being called as 
 * a result of a change happening within the callbacks themselves.
 */
public abstract class EditableTextWatcher implements TextWatcher {

    private boolean editing;

    @Override
    public final void beforeTextChanged(CharSequence s, int start, 
                                                    int count, int after) {
        if (editing)
            return;

        editing = true;
        try {
            beforeTextChange(s, start, count, after);
        } finally {
            editing = false;
        }
    }

    protected abstract void beforeTextChange(CharSequence s, int start, 
                                                     int count, int after);

    @Override
    public final void onTextChanged(CharSequence s, int start, 
                                                int before, int count) {
        if (editing)
            return;

        editing = true;
        try {
            onTextChange(s, start, before, count);
        } finally {
            editing = false;
        }
    }

    protected abstract void onTextChange(CharSequence s, int start, 
                                            int before, int count);

    @Override
    public final void afterTextChanged(Editable s) {
        if (editing)
            return;

        editing = true;
        try {
            afterTextChange(s);
        } finally {
            editing = false;
        }
    }

    public boolean isEditing() {
        return editing;
    }

    protected abstract void afterTextChange(Editable s);
}

Поэтому, когда используется вышеописанное, любые вызовы setText(), происходящие внутри TextWatcher, не будут вызывать снова вызов TextWatcher:

/**
 * A setText() call in any of the callbacks below will not result in TextWatcher being 
 * called again.
 */
public class MyTextWatcher extends EditableTextWatcher {

    @Override
    protected void beforeTextChange(CharSequence s, int start, int count, int after) {
    }

    @Override
    protected void onTextChange(CharSequence s, int start, int before, int count) {
    }

    @Override
    protected void afterTextChange(Editable s) {
    }
}

Ответ 6

Вы также можете использовать метод hasFocus():

public void onTextChanged(CharSequence s, int start,
     int before, int count) {
     if (Field2.hasfocus()){
         Field1.setText("");
     }
   }

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

Ответ 7

проверьте строку перед тем, как установить еще один EditText на пустой. если Field1 пусто, то зачем нужно снова менять ("")? поэтому вы можете проверить размер своей строки с s.lenght() или любым другим решением

Другой способ, которым вы можете проверить длину строки, это:

String sUsername = Field1.getText().toString();
if (!sUsername.matches(""))
{
// do your job
}

Ответ 8

Я написал собственное расширение для этого, очень полезно для меня. (Котлин)

Вы можете написать только так:

editText.customAfterTextChanged { editable -> 
    //You have accessed the editable object. 
}

Мое расширение:

fun EditText.customAfterTextChanged(action: (Editable?)-> Unit){
    this.addTextChangedListener(object : TextWatcher {
       override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
       override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {}
       override fun afterTextChanged(editable: Editable?) {
        action(editable)
    }
})}