Android Studio: урок Kotlin — обработка ввода текста с TextWatcher

Поле ввода текста встречается в каждом втором приложении: логин, поиск, комментарий. Но иногда нужно не просто прочитать то, что ввёл пользователь, а мгновенно реагировать на каждое нажатие клавиши. В Android Studio для этого существует специальный интерфейс — TextWatcher. На этом занятии мы напишем небольшой проект на Kotlin и разберёмся, как с его помощью следить за вводом, подсчитывать символы и управлять видимостью кнопки. Материал рассчитан на начинающих и поможет сделать интерфейс более отзывчивым.


Что умеет TextWatcher

TextWatcher — это слушатель, который прикрепляется к EditText и получает три события. beforeTextChanged вызывается до того, как текст изменится, и позволяет узнать старый контент. onTextChanged срабатывает прямо в момент изменения — здесь удобно реагировать на новые символы. afterTextChanged выполняется после завершения изменений, когда текст уже обновлён. Для большинства задач достаточно именно последнего метода: можно проверить длину строки, отфильтровать нежелательные символы или изменить состояние других View.


Разметка экрана для примера

Создайте простой LinearLayout с EditText, TextView для отображения количества введённых символов и кнопкой, которая будет активна только при непустом поле.

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="24dp">

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Введите текст" />

    <TextView
        android:id="@+id/tvCounter"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="14sp"
        android:layout_marginTop="8dp" />

    <Button
        android:id="@+id/btnSubmit"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Отправить"
        android:layout_marginTop="16dp"
        android:enabled="false" />
</LinearLayout>

Подключаем TextWatcher в Activity

В MainActivity.kt получим ссылки на элементы и добавим слушатель к EditText. В методе afterTextChanged будем обновлять счётчик символов и включать или отключать кнопку.

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val editText = findViewById<EditText>(R.id.editText)
        val tvCounter = findViewById<TextView>(R.id.tvCounter)
        val btnSubmit = findViewById<Button>(R.id.btnSubmit)

        editText.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
                // не используется
            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                // не используется
            }

            override fun afterTextChanged(s: Editable?) {
                val length = s?.length ?: 0
                tvCounter.text = "Символов: $length"
                btnSubmit.isEnabled = length > 0
            }
        })
    }
}

Упрощённая версия с лямбдой

TextWatcher имеет три метода, но Kotlin позволяет обойтись без написания громоздкого анонимного класса. Можно создать расширение, которое преобразует лямбду в TextWatcher, или использовать готовый doOnTextChanged из AndroidX core-ktx. Добавим зависимость и используем краткий синтаксис.

dependencies {
    implementation("androidx.core:core-ktx:1.12.0")
}

Теперь код сокращается до пары строк:

editText.doOnTextChanged { text, _, _, _ ->
    val length = text?.length ?: 0
    tvCounter.text = "Символов: $length"
    btnSubmit.isEnabled = length > 0
}

Фильтрация ввода: запрещаем пробелы

Иногда нужно ограничить допустимые символы. Например, не разрешать вводить пробелы в поле логина. Это делается в методе beforeTextChanged или с помощью InputFilter, но проще всего добавить проверку в afterTextChanged и удалить лишние символы.

override fun afterTextChanged(s: Editable?) {
    s?.let {
        if (it.contains(" ")) {
            val filtered = it.toString().replace(" ", "")
            editText.setText(filtered)
            editText.setSelection(filtered.length) // курсор в конец
        }
    }
}

Практические советы

  • Не делайте сложных операций в TextWatcher. Он вызывается при каждом изменении, поэтому долгие вычисления или запросы к серверу здесь неуместны. Для этого используйте debounce с корутинами.
  • Избегайте рекурсивных вызовов. Если внутри afterTextChanged вы меняете текст, это снова вызовет TextWatcher. Устанавливайте флаг-защиту или временно отключайте слушатель.
  • Используйте InputFilter для масок и ограничений. TextWatcher хорош для реакции на текст, но для жёсткого контроля ввода (например, только цифры) лучше подходит InputFilter.

Коротко о главном

Этот урок в среде Android Studio на языке Kotlin познакомил вас с TextWatcher — удобным инструментом для отслеживания ввода. Вы научились прикреплять его к EditText, обновлять счётчик символов и управлять доступностью кнопки. Теперь ваши поля ввода могут реагировать на каждое действие пользователя. Попробуйте добавить проверку минимальной длины пароля или форматирование номера телефона по мере набора — это закрепит навык.