Какие методы вызываются при потере фокуса у кастомной View
Что проверяют
Знаете ли вы точную сигнатуру колбэков фокуса, а не только общее «есть слушатель». Обычно за этим стоит кастомное поле ввода или TV-интерфейс. Следом спрашивают, почему после clearFocus() фокус вдруг оказался на другом элементе.
Как отвечать
Основной метод в кастомной View:
onFocusChanged(gainFocus: Boolean, direction: Int, previouslyFocusedRect: Rect?): protected-метод, вызывается и при получении, и при потере фокуса.directionпоказывает направление перехода (FOCUS_DOWN,FOCUS_FORWARDи другие),previouslyFocusedRectбываетnull. Вызовsuperобязателен: базовая реализация уведомляет слушателя и IME и перерисовывает view;OnFocusChangeListener.onFocusChange(v, hasFocus): внешний слушатель черезsetOnFocusChangeListener, вызывается изonFocusChangedбазового класса;drawableStateChanged(): смена фокуса обновляет drawable state, и селекторы сstate_focusedпереключаются сами. Если фон рисуете вручную, реагируйте здесь;onWindowFocusChanged(hasWindowFocus): другое событие, фокус окна. Срабатывает, когда поверх открылся диалог или шторка уведомлений, а фокус внутри окна у view при этом сохраняется;- уровень ViewGroup:
requestChildFocusиclearChildFocus, а для всего дереваViewTreeObserver.OnGlobalFocusChangeListenerс парой старого и нового view.
Чтобы кастомная View вообще получала фокус, нужен isFocusable = true, а для работы от касаний ещё isFocusableInTouchMode = true. В режиме касаний большинство view фокус не берут, и это норма. В Compose для этого есть Modifier.onFocusChanged { it.isFocused }.
Где спотыкаются
Пишут onFocusChanged(boolean hasFocus) с одним параметром. Такого метода нет, и @Override не скомпилируется.
Не вызывают super.onFocusChanged. Слушатель перестаёт срабатывать, и выпадает остальная логика базового класса.
Путают потерю фокуса view и потерю фокуса окна. Открытие диалога вызовет onWindowFocusChanged(false), но не onFocusChanged, и сохранение текста, привязанное к потере фокуса, не сработает. Ещё сюрприз: вне режима касаний после clearFocus() система сама отдаёт фокус первому подходящему view сверху.