>>
Правильный способ перемещения курсора в конец EditText
Проблема, с которой вы столкнулись, очень распространена среди начинающих Android-разработчиков. Основная причина — изменение текста через setText() может сбросить позицию курсора, особенно если в EditText установлены слушатели (TextWatcher) или если текст меняется во время обработки другого события.
Вот несколько надёжных решений на Kotlin:
Решение 1: Использование Editable и append()
Самый простой и надёжный способ — не использовать setText(), а работать напрямую с Editable через метод append(). Он автоматически добавляет текст в конец и сохраняет курсор в конце:
button.setOnClickListener {
editText.append(" кг")
}
Этот метод гарантированно помещает новый текст в конец существующего, а курсор остаётся после добавленного текста. Никаких дополнительных вызовов setSelection() не требуется.
Решение 2: setText() с последующим setSelection()
Если вам всё же нужно использовать setText() (например, для полной замены текста), то правильный порядок действий:
button.setOnClickListener {
val newText = editText.text.toString() + " кг"
editText.setText(newText)
// Важно: setSelection нужно вызывать после того, как текст был установлен
editText.setSelection(newText.length)
}
Почему это может не работать? Потому что setText() может внутренне запустить цепочку событий, которые сбрасывают выделение. Чтобы обойти это, можно использовать TextWatcher или отложить вызов:
button.setOnClickListener {
val newText = editText.text.toString() + " кг"
editText.setText(newText)
editText.post {
editText.setSelection(newText.length)
}
}
Метод post() помещает выполнение кода в конец очереди сообщений, что гарантирует, что все внутренние обновления EditText уже завершены.
Решение 3: Использование InputConnection
Более продвинутый способ — использовать InputConnection, который даёт прямой доступ к редактированию текста:
button.setOnClickListener {
val ic = editText.onCreateInputConnection(EditorInfo())
ic?.commitText(" кг", 1)
}
Этот метод эмулирует ввод текста с клавиатуры, поэтому курсор всегда оказывается в конце.
Важные рекомендации
- Фокус: Перед перемещением курсора убедитесь, что EditText имеет фокус. Вызовите
editText.requestFocus() перед setSelection().
- TextWatcher: Если у вас установлен
TextWatcher, он может вмешиваться в позиционирование курсора. Проверьте, не сбрасывает ли он позицию в методе afterTextChanged().
- Тип ввода: Некоторые типы ввода (например,
android:inputType="textMultiLine") могут вести себя по-разному. Протестируйте на разных конфигурациях.
- Android версии: На старых версиях Android (API < 21) могут быть баги с
setSelection(). Используйте post() для совместимости.
Итоговый рекомендуемый код
button.setOnClickListener {
editText.append(" кг")
// Если нужно, чтобы курсор был точно в конце (например, после удаления части текста)
editText.post {
editText.setSelection(editText.text.length)
}
}
Этот подход сочетает простоту append() и надёжность post(). Он работает на всех версиях Android и во всех сценариях.
<<>>
Альтернативный подход: Использование Selection и Spannable
Если вы работаете с форматированным текстом (SpannableString или SpannableStringBuilder), методы append() могут не подойти. В этом случае используйте Selection.setSelection() для явного управления курсором:
import android.text.Selection
import android.text.Spannable
button.setOnClickListener {
val text = editText.text
if (text is Spannable) {
val newText = text.toString() + " кг"
editText.setText(newText)
Selection.setSelection(editText.text as Spannable, newText.length)
} else {
editText.append(" кг")
}
}
Когда это полезно?
- Когда текст содержит изображения (ImageSpan) или ссылки (URLSpan).
- Когда нужно сохранить существующие спаны (форматирование) при добавлении текста.
- Когда вы используете кастомные EditText с переопределёнными методами работы с текстом.
Дополнительный совет
Для случаев, когда курсор упорно не хочет перемещаться, попробуйте сбросить фокус и снова его установить:
button.setOnClickListener {
editText.clearFocus()
editText.append(" кг")
editText.requestFocus()
editText.post {
editText.setSelection(editText.text.length)
}
}
Этот "жёсткий" сброс фокуса решает проблемы, связанные с багами в некоторых версиях Android или кастомных прошивках.