
Многие мобильные приложения уже могут конкурировать с полноценными десктопными версиями, а иногда и превосходить их. Офисные пакеты, фоторедакторы и IDE вполне неплохо работают на портативных девайсах. Samsung, например, даже сделал специальный режим DeX Mode, который позволяет подключить к смартфону монитор и периферию.
А скорый релиз Windows 11 с возможностью устанавливать любые APK-файлы прямо намекает, что пора озаботиться поддержкой десктопных режимов в своих мобильных приложениях. Один из шагов к этому — добавить полноценную поддержку клавиатуры, чем сегодня и займёмся.
Под катом разберём навигацию по RecyclerView, привязку горячих клавиш к toolbar menu, добавим кастомные сочетания и покажем пользователям, как ими пользоваться.
Навигация по RecyclerView
Google в RecyclerView (в отличие от ListView) не стал добавлять нативную поддержку клавиатур и D-падов для навигации, поэтому придётся добавлять её самим.
Реализация навигации во многом зависит от используемого layout-менеджера, наличия фокусируемых вьюх (focusable views) в списке, возможности мультивыбора и других деталей. Но базовый подход не поменяется. Для добавления поддержки клавиатуры в RecyclerView нужно только дополнить адаптер, не затрагивая остальную часть приложения.
Просто регистрируем OnKeyListener в адаптере на прикрепленном списке, чтобы начать принимать нажатия кнопок:
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) { super.onAttachedToRecyclerView(recyclerView) recyclerView.setOnKeyListener{_, keyCode, event-> if (event.action!= KeyEvent.ACTION_DOWN) { return@setOnKeyListener false } when (keyCode) { KeyEvent.KEYCODE_DPAD_DOWN-> selectNext(recyclerView) KeyEvent.KEYCODE_DPAD_UP-> selectPrevious(recyclerView) else -> return@setOnKeyListener false } return@setOnKeyListener true } }
Сложность реализации методов selectNext() и selectPrevious() зависит целиком от ваших пожеланий. В общем случае всё сводится к:
private fun selectNext(recyclerView: RecyclerView) { val oldSelectedPosition = selectedPosition selectedPosition = if (selectedPosition.isLast()) { 0 } else { selectedPosition + 1 } notifyItemChanged(selectedPosition) notifyItemChanged(oldSelectedPosition) recyclerView.smoothScrollToPosition(selectedPosition) }
Горячие клавиши для toolbar menu
Пожалуй, наиболее простой способ добавить шорткаты в приложение — использовать атрибуты android:alphabeticShortcut и android:numericShortcut в ваших <menu>-файлах.
Для примера меню вида:
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/menuAddTask" android:icon="@drawable/ic_add_task" app:showAsAction="always" android:title="@string/add_task" android:alphabeticShortcut="n"/> <item android:id="@+id/menuFilter" android:icon="@drawable/ic_filter" app:showAsAction="always" android:title="@string/show_filter" android:alphabeticShortcut="f"/> </menu>
Такое меню будет, помимо обычных нажатий, автоматически поддерживать сочетания Ctrl+F и Ctrl+N для выполнения необходимых действий, описанных в методе onOptionsItemSelected().
Но выносить все действия, для которых хочется иметь горячие клавиши, в шорткаты довольно неудобно — иногда действие просто не подходит для меню, а иногда хочется чего-то кроме комбинации Ctrl с цифрой или буквой.
И для этого можно сделать кастомные хоткеи.
Настраиваем кастомные горячие клавиши
Для более тонкой настройки класс KeyEvent предлагает набор методов, чтобы определить, зажата ли дополнительная клавиша во время срабатывания метода onKey:
isCtrlPressed() isShiftPressed() isFunctionPressed() isAltPressed()
Возьмём для примера to-do-лист, и назначим удаление выбранной задачи по нажатию Shift+Delete. Для этого достаточно добавить в слушатель нажатий из предыдущего примера такой код:
if (keyCode == KeyEvent.KEYCODE_DEL && event.isShiftPressed && event.repeatCount == 0) { deleteSelectedTask() }
Обратите внимание на repeatCount — если юзер зажмёт клавиши, то в слушатель посыпется непрерывный поток событий, что и будет отражено в значении этого параметра.
Рассказываем о горячих клавишах пользователям
Мы не можем рассчитывать, что пользователь пойдет смотреть FAQ на экране саппорта, поэтому в Android 7.0 добавили сочетание Meta+/ (или Win+/ на соответствующих клавиатурах), которое открывает поп-ап с глобальными горячими клавишами системы. В него мы и добавим наши горячие клавиши для удаления или создания новой задачи.
Для этого нужно пер��определить метод onProvideKeyboardShortcuts() и добавить в него новую группу хоткеев:
@TargetApi(Build.VERSION_CODES.N) override fun onProvideKeyboardShortcuts(data: MutableList<KeyboardShortcutGroup>, menu: Menu?, deviceId: Int) { super.onProvideKeyboardShortcuts(data, menu, deviceId) val additionalShortcuts = mutableListOf<KeyboardShortcutInfo>() with(additionalShortcuts) { add(KeyboardShortcutInfo("Delete task", KeyEvent.KEYCODE_DEL, KeyEvent.META_SHIFT_ON)) add(KeyboardShortcutInfo("New task", KeyEvent.KEYCODE_N, KeyEvent.META_CTRL_ON)) } data.add(KeyboardShortcutGroup("My app custom shortcuts", additionalShortcuts)) }
Результат выглядит так:

Для устройств с версией ОС меньше 7.0 придётся делать своё решение:
if (keyCode == KeyEvent.KEYCODE_SLASH && event.isMetaPressed && Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { showCustomShortcutsDialogFragment() return true }
Заключение
Поддержка клавиатуры в Аndroid-приложениях не требует каких-то значительных усилий и реализуется буквально несколькими методами. А значит — это очень простой способ улучшить пользовательский опыт в проекте. И им точно не стоит пренебрегать.
