Многие мобильные приложения уже могут конкурировать с полноценными десктопными версиями, а иногда и превосходить их. Офисные пакеты, фоторедакторы и 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-приложениях не требует каких-то значительных усилий и реализуется буквально несколькими методами. А значит — это очень простой способ улучшить пользовательский опыт в проекте. И им точно не стоит пренебрегать.
Комментарии (16)
ld100
10.08.2021 20:42Офисные пакеты, фоторедакторы и IDE вполне неплохо работают на портативных девайсах.
Это какие IDE вполне неплохо работают на портативных девайсах? Я не придираюсь, просто интересуюсь. Последний раз когда интересовался IDE для айпада - самый максимум что смог найти - это простенький текстовый редактор с подсветкой кода, умеющий работать с GitHub.
maxcat
11.08.2021 05:41Visual Studio неплохо работает на виндовых планшетах
Ну а если говорить о смартфонах переростках, то на андроиде есть AIDE
ris58h
11.08.2021 00:03+2Отлично! Ещё бы статью про оптимизацию андроид приложения для декстопа - сейчас это основная боль от многих приложений в dex режиме.
402d
15.08.2021 17:07Вы так легко закончили, что не составит труда подключить поддержку клавиатуры. Мой опыт протестует. Поддержку клавиатуры там придется с болью вкручивать. Самое простое прописать по 4 свойства перехода и поправить бекграунды с учётом текущий или нет. Засада начинается, когда курсор не хочет перескакивать в шапку на меню элементы .
В общем до фига работы, которую оценят единицы пользователей.
Sot
15.08.2021 18:32Готовься не готовься, а Google не готов поддерживать Numpad Enter :) https://issuetracker.google.com/issues/134205188
virtusha
15.08.2021 18:32Поздно! APK-файлы в прошлом
Krushiler
22.08.2021 11:40да нет. если вы про aab, то он ещё раньше в google play появился. просто для разработчиков он необязательным был. и это хорошо, что gp полностью на этот формат переводят, ибо не надо будет качать ресурсы, которые не предназначены для твоего телефона. а вот кнопка build apk в android studio никуда не исчезнет. можно будет так же собрать апкшку и закинуть её в microsoft store. да и вообще хоть куда.
iddqdpwn
15.08.2021 18:32Google в RecyclerView (в отличие от ListView) не стал добавлять нативную поддержку клавиатур и D-падов для навигации, поэтому придётся добавлять её самим.
Когда разрабатывал приложение под Android TV навигация по элементам списка RecyclerView (как и по всем focusable вьюхам в разметке) при помощи D-Pad осуществлялась нативно без определения KeyEvent'ов, так же срабатывала после return@setOnKeyListener false. Или я не верно понял эту фразу?
quaer
Какая выгода от установки приложения Android на Windows для разработчика?
Что с лицензированием? Пиратством?
Не дешевле ли, проще, лучше написать на .NET?
Просто заменить RecyclerView на ListVew?
linreal Автор
Поддержка горячих клавиш, описанная в статье, не ограничивается списками, а менять RecyclerView обратно на откровенно устаревший ListView, чтобы решить проблемы навигации с клавиатуры — не очень хорошее решение.
quaer
Ради чего покупать видеоредактор, заточенный под Android, если есть заточенные под Windows? Магазин Amazon популярностью не пользуется, родной магазин Windows тоже вроде не особо популярен.
Приложения под Android как правило заточены под небольшой экран и пальцеориентированы, что накладывает отпечаток на интерфейс: большие размеры кнопок относительно доступной площади экрана, прокрутка без скроллбара, отсутствие всплывающих подсказок. Ради чего мучиться с такими приложениями на ПК?
"откровенно устаревший ListView" разве не работает?
maxcat
вы правы, на андроиде не умеют или не хотят делать универсальный гуй. Универсальный гуй относительно умели делать в UWP, но по странным причинам MS решила убить свой натив и натощить сомнительностей с андроида и веба
Neikist
К сожалению иногда просто нет десктопного приложения. Есть мобильные приложения и сайт. А веб приложениями пользоваться сильно на любителя.
Лист вью работает, но он тормозной все таки на более менее больших списках. Плюс апи менее гибкое.
quaer
Вы не изучали глубже вопрос с пиратством? Если можно будет apk файлы запускать на Windows, кажется, что воровать станет проще.
Даже при использовании кэширования с convertView?
Neikist
Что воровать? apk файлы из гугл стора и так на всякие apkpure чуть ли не мгновенно приезжают. И не вижу в этом ничего плохого, одни плюсы. Я к пиратству отношусь просто, есть те кто за контент платят — они и дальше будут платить за удобство, сервис и чтобы поддержать автора. Есть те у кого денег мало, те если не получат доступа к пиратскому контенту и пользоваться не будут так как все равно платить не станут из за ограниченного бюджета. Есть принципиальные пираты которые уж точно не будут покупать. Так что хуже не станет, скорее даже лучше, поскольку пользовательская база расширится у тех кто поддержит стор амазона и адаптирует к windows приложение хотя бы минимально.
З.Ы. говорю это как человек работающий в небольшой компании которая как раз за комиссию позволяет пользователям книги продавать читателям своим.
Т.е. вы хотите городить из ListView кривой и недоделанный аналог RecyclerView? А зачем?