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

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

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

Источник: https://habr.com/ru/company/funcorp/blog/571952/


Интересные статьи

Интересные статьи

Добро пожаловать в очередной выпуск Windows Terminal! Этот выпуск обновляет Windows Terminal Preview до версии 1.8 и основной Windows Terminal до версии 1.7. Обе сборки м...
Наверно я не один такой, кто столкнулся с проблемой отсутствия границ окон в новых системах windows, ведь зачем-то их убрали с одним из обновлений. Спрашивают многие, а в...
Уважаемые друзья, в предыдущих публикациях мы говорили об основах информационной безопасности, законодательстве по защите персональных данных и критической информационной инфраструкт...
В прошлой статье я рассказывал про основы JWT. Если на пальцах, то это просто ключ, с помощью которого мы открываем дверь к приватным ресурсам. А что, если этот ключ украдут (точнее, сделают ду...
Предыстория У меня есть убогий дешевый планшет на Windows 10 с одним гигабайтом оперативной памяти и 16 гигабайтами места, в пределах которого установлен Windows 10. Чтобы Windows 10 мог х...