Android: Кастомизация TextWatcher для обработки ввода в EditText

Для работы с элементов EditText когда-нибудь вам придётся организовывать слежение за вводов пользователя. Есть стандартный OnKeyListener, но он как-то странно работает 0_о. Но обо всём попорядку.

OnKeyListener

Можно на EditText повесить OnKeyListener, который будет отслеживать нажатия на виртуальной клавиатуре. Как-то так:

((EditText)findViewById(R.id.resultNumericSystemTE)). setOnKeyListener(new View.OnKeyListener(){
   public boolean onKey(View v, int keyCode, KeyEvent event){
      return false;
      }
   }
);

Вроде всё нормально, в keyCode у нас ID нажатой клавиши. По сути всё, можем принимать нажатую кнопку или отменять ввод. Вот только это событие прокает почему-то лишь на кнопки по манипулированию: удаление символа, Enter и т.д.

TextWatcher

Ок, ищем другое решение. Находим интересный класс TextWatcher. Пробуем повесить на наш EditText:

TextWatcher inputTW = 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) {
                  
    }

};

((EditText)findViewById(R.id.MyTE)).addTextChangedListener(inputTW);

Супер! Теперь можно что-то сделать с EditText до и после нажатия. Вот только есть одна проблемка – нету ссылки на сам EditText внутри TextWatcher. Можно конечно обращаться внутри обработчика глобально, типо:

public void afterTextChanged(Editable s) { 
   EditText et = (EditText)findViewById(R.id.MyTE);
}

Да, будет всё отлично работать, но тогда при написании обработчиков на все EditText придётся дублировать кучу кода. А хотелось бы где-то прописать один раз этот, так сказать, шаблон поведения, а потом юзать его.

Свой TextWatcher

И да, можно *__* В Java есть implements — это дополнение к определению класса, реализующего некоторый интерфейс(ы). Создаём свой класс. Как пример, хотим, чтобы в EditText юзер не мог ввести больше 2 символов:

public class TextWatcherP implements TextWatcher {
	
   public EditText editText;
	
   public TextWatcherP(EditText et){
      super();
      editText = et;
   }
   public void afterTextChanged(Editable s) { 
      if(editText.getText().length() == 3){
      editText.setText(editText.getText().subSequence(0, editText.getText().length()-1));
      }
   }
   public void beforeTextChanged(CharSequence s, int start, int count, int after){ 
    	
    }
    public void onTextChanged(CharSequence s, int start, int before, int count) {
          
    }
}

По сравнению с базовым классом, наш в конструкторе принимает ссылку на EditText, что устраняет проблему описанную выше. Использовать же просто:

EditText et = (EditText)findViewById(R.id.MyTE)
TextWatcherP inputTextWatcher= new TextWatcherP(et);
et.addTextChangedListener(inputTextWatcher);
  Категории: Android, Коддинг
  • Pingback: Android: программное отключение автокоррекции в EditText | Suvitruf's Blog()

  • Дмитрий

    Полезная статья, сам использовал данный класс при написании одного приложения.
    Также хотел применить его для реализации маски ввода в edittext, чтобы текст вводился таким образом: “123”, далее “1 234″, далее “12 345″, далее “123 456″ и т.д. Так и не смог этого сделать. Несмотря на то, что в логкат выводилось так как мне нужно, в edittext попадало без разрывов между разрядами. Может как-нибудь добью эту проблему.

  • Дмитрий

    Спасибо огромное, именно это и искал TextWatcher то что нужно.

  • Сергей

    ОГРОМНОЕ спасибо, наконец то дошло, как сделать то что я хочу.

  • Ринат

    Чтоб не писать свой класс можно объявить EditText с final :
    final EditText et = (EditText)findViewById(R.id.MyTE)

    Тогда уже в TextWatcher можно будет к et прямо обращаться.

  • Виталий

    А если я хочу один обработчик для многих EditText, как в этом случае определять какой именно EditText инициировал вызов метода?

    • http://suvitruf.ru Suvitruf

      К примеру, сделать свой класс, унаследовав его от TextWatcher.