Готовимся к Windows 11: добавляем поддержку полноценной клавиатуры в Android-приложение

62da0256d47ba7865b8f6db4ffa7f691.jpeg

Многие мобильные приложения уже могут конкурировать с полноценными десктопными версиями, а иногда и превосходить их. Офисные пакеты, фоторедакторы и 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 в ваших

-файлах.

Для примера меню вида:


   

   

Такое меню будет, помимо обычных нажатий, автоматически поддерживать сочетания 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, menu: Menu?, deviceId: Int) {
  super.onProvideKeyboardShortcuts(data, menu, deviceId)
  val additionalShortcuts = mutableListOf()
  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))
}

Результат выглядит так:

image-loader.svg

Для устройств с версией ОС меньше 7.0 придётся делать своё решение:

if (keyCode == KeyEvent.KEYCODE_SLASH && event.isMetaPressed && Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
   showCustomShortcutsDialogFragment()
   return true
}

Заключение

Поддержка клавиатуры в Аndroid-приложениях не требует каких-то значительных усилий и реализуется буквально несколькими методами. А значит — это очень простой способ улучшить пользовательский опыт в проекте. И им точно не стоит пренебрегать.

© Habrahabr.ru