На устройствах с большим экраном пользователи часто взаимодействуют с приложениями с помощью клавиатуры, мыши, трекпада, стилуса или геймпада. Чтобы ваше приложение могло принимать ввод с внешних устройств, выполните следующие действия:
- Проверьте базовую поддержку клавиатуры , например Ctrl+Z для отмены, Ctrl+C для копирования и Ctrl+S для сохранения. См. Обработка действий клавиатуры для списка сочетаний клавиш по умолчанию.
- Проверьте поддержку расширенной клавиатуры , например, навигацию с помощью клавиши Tab и клавиш со стрелками, подтверждение ввода текста с помощью клавиши Enter , а также воспроизведение и пауза с помощью клавиши пробела в мультимедийных приложениях.
- Тестируйте основные взаимодействия с мышью , включая щелчок правой кнопкой мыши для вызова контекстного меню, изменение значка при наведении курсора, а также события прокрутки колесика мыши или трекпада на пользовательских компонентах.
- Тестируйте устройства ввода, специфичные для приложения , такие как стилус, игровые контроллеры и MIDI-контроллеры музыкальных приложений.
- Рассмотрите расширенную поддержку ввода , которая могла бы выделить приложение в среде настольных компьютеров, например, сенсорную панель в качестве кроссфейдера для приложений DJ, захват мыши для игр и сочетания клавиш для пользователей, ориентированных на клавиатуру.
Клавиатура
То, как ваше приложение реагирует на ввод с клавиатуры, способствует пользовательскому опыту на большом экране. Существует три типа ввода с клавиатуры: навигация , нажатия клавиш и сочетания клавиш .
Навигация
Клавиатурная навигация редко реализуется в приложениях с сенсорным управлением, но пользователи ожидают ее, когда используют приложение и держат руки на клавиатуре. Клавиатурная навигация может быть необходима на телефонах, планшетах, складных устройствах и настольных устройствах для пользователей с потребностями в доступности.
Для многих приложений навигация с помощью клавиш со стрелками и клавиш Tab автоматически обрабатывается фреймворком Android. Например, некоторые компонуемые объекты по умолчанию фокусируются, например Button
или компонуемый объект с модификатором clickable
; навигация с помощью клавиатуры, как правило, должна работать без дополнительного кода. Чтобы включить навигацию с помощью клавиатуры для пользовательских компонуемых объектов, которые по умолчанию не фокусируются, добавьте модификатор focusable
:
var color by remember { mutableStateOf(Green) } Box( Modifier .background(color) .onFocusChanged { color = if (it.isFocused) Blue else Green } .focusable() ) { Text("Focusable 1") }
Для получения дополнительной информации см. раздел Создание компонуемого фокусируемого объекта .
Когда фокус включен, фреймворк Android создает навигационное отображение для всех фокусируемых компонентов на основе их положения. Обычно это работает так, как и ожидалось, и дальнейшая разработка не требуется.
Однако Compose не всегда определяет правильный следующий элемент для навигации с помощью вкладок для сложных компонуемых элементов, таких как вкладки и списки, например, когда один из компонуемых элементов представляет собой горизонтальный прокручиваемый элемент, который не полностью виден.
Чтобы управлять поведением фокуса, добавьте модификатор focusGroup
к родительскому компонуемому элементу коллекции компонуемых элементов. Фокус перемещается на группу, затем через группу, прежде чем перейти к следующему фокусируемому компоненту, например:
Row {
Column(Modifier.focusGroup()) {
Button({}) { Text("Row1 Col1") }
Button({}) { Text("Row2 Col1") }
Button({}) { Text("Row3 Col1") }
}
Column(Modifier.focusGroup()) {
Button({}) { Text("Row1 Col2") }
Button({}) { Text("Row2 Col2") }
Button({}) { Text("Row3 Col2") }
}
}
Для получения дополнительной информации см. раздел Обеспечение согласованной навигации с помощью фокус-групп .
Проверьте доступ к каждому элементу пользовательского интерфейса вашего приложения, используя только клавиатуру. Часто используемые элементы должны быть доступны без мыши или сенсорного ввода.
Помните, что поддержка клавиатуры может быть необходима пользователям с ограниченными возможностями.
Нажатия клавиш
Для ввода текста, который будет обрабатываться экранной виртуальной клавиатурой ( IME ), например,TextField
, приложения должны вести себя ожидаемо на устройствах с большим экраном без дополнительной разработки. Для нажатий клавиш, которые не могут быть предсказаны фреймворком, приложения должны сами обрабатывать поведение. Это особенно актуально для приложений с пользовательскими представлениями.
Вот несколько примеров: приложения для чата, которые используют клавишу Enter для отправки сообщения, мультимедийные приложения, которые запускают и останавливают воспроизведение с помощью клавиши пробела , и игры, которые управляют движением с помощью клавиш w , a , s и d .
Вы можете обрабатывать отдельные нажатия клавиш с помощью модификатора onKeyEvent
, который принимает лямбду, вызываемую, когда измененный компонент получает событие клавиши. Свойство KeyEvent#type
позволяет вам определить, является ли событие нажатием клавиши ( KeyDown
) или отпусканием клавиши ( KeyUp
):
Box(
modifier = Modifier.focusable().onKeyEvent {
if(
it.type == KeyEventType.KeyUp &&
it.key == Key.S
) {
doSomething()
true
} else {
false
}
}
) {
Text("Press S key")
}
В качестве альтернативы вы можете переопределить обратный вызов onKeyUp()
и добавить ожидаемое поведение для каждого полученного кода клавиши:
kotlin
override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
return when (keyCode) {
KeyEvent.KEYCODE_ENTER -> {
sendChatMessage()
true
}
KeyEvent.KEYCODE_SPACE -> {
playOrPauseMedia()
true
}
else -> super.onKeyUp(keyCode, event)
}
}
Событие onKeyUp
происходит при отпускании клавиши. Использование обратного вызова избавляет приложения от необходимости обрабатывать несколько событий onKeyDown
, если клавиша удерживается или отпускается медленно. Игры и приложения, которым необходимо определять момент нажатия клавиши или удерживает ли пользователь клавишу, могут прослушивать событие onKeyDown
и самостоятельно обрабатывать повторяющиеся события onKeyDown
.
Для получения дополнительной информации см. раздел Обработка действий клавиатуры .
Ярлыки
При использовании аппаратной клавиатуры ожидаются общие сочетания клавиш, включающие клавиши Ctrl , Alt , Shift и Meta . Если приложение не реализует сочетания клавиш, это может раздражать пользователей. Продвинутые пользователи также оценят сочетания клавиш для часто используемых задач, характерных для приложения. Сочетания клавиш упрощают использование приложения и отличают его от приложений, не имеющих сочетаний клавиш.
Некоторые распространенные сочетания клавиш включают Ctrl+S (сохранить), Ctrl+Z (отменить) и Ctrl+Shift+Z (повторить). Список сочетаний клавиш по умолчанию см. в разделе Обработка действий клавиатуры .
Объект KeyEvent
имеет следующие атрибуты, которые указывают, нажаты ли клавиши-модификаторы:
Например:
Box(
Modifier.onKeyEvent {
if (it.isAltPressed && it.key == Key.A) {
println("Alt + A is pressed")
true
} else {
false
}
}
.focusable()
)
Более подробную информацию см. в следующих источниках:
Стилус
Многие устройства с большим экраном поставляются со стилусом. Приложения Android обрабатывают стилусы как сенсорный ввод. Некоторые устройства также могут иметь планшет для рисования USB или Bluetooth, например Wacom Intuos . Приложения Android могут получать вход Bluetooth, но не USB-вход.
Чтобы получить доступ к объектам Stylus MotionEvent
, добавьте модификатор pointerInteropFilter
к поверхности рисования. Реализуйте класс ViewModel
с методом, который обрабатывает события движения; передайте метод как лямбда-функцию onTouchEvent
модификатора pointerInteropFilter
:
@Composable
@OptIn(ExperimentalComposeUiApi::class)
fun DrawArea(modifier: Modifier = Modifier) {
Canvas(modifier = modifier
.clipToBounds()
.pointerInteropFilter {
viewModel.processMotionEvent(it)
}
) {
// Drawing code here.
}
}
Объект MotionEvent
содержит информацию о событии:
-
MotionEvent#getToolType()
возвращаетTOOL_TYPE_FINGER
,TOOL_TYPE_STYLUS
илиTOOL_TYPE_ERASER
в зависимости от инструмента, который соприкоснулся с дисплеем. -
MotionEvent#getPressure()
сообщает о физическом давлении, приложенном к стилусу (если поддерживается) -
MotionEvent#getAxisValue()
сMotionEvent.AXIS_TILT
иMotionEvent.AXIS_ORIENTATION
обеспечивают физический наклон и ориентацию стилуса (если поддерживается)
Исторические моменты
Android группирует события ввода и доставляет их один раз за кадр. Стилус может сообщать о событиях с гораздо более высокой частотой, чем дисплей. При создании приложений для рисования проверяйте события, которые могут быть в недавнем прошлом, используя API getHistorical
:
-
MotionEvent#getHistoricalX()
-
MotionEvent#getHistoricalY()
-
MotionEvent#getHistoricalPressure()
-
MotionEvent#getHistoricalAxisValue()
Отторжение ладони
Когда пользователи рисуют, пишут или взаимодействуют с вашим приложением с помощью стилуса, они иногда касаются экрана ладонью. Событие касания (установленное на ACTION_DOWN
или ACTION_POINTER_DOWN
) может быть передано в ваше приложение до того, как система распознает и проигнорирует непреднамеренное касание ладонью.
Android отменяет события касания ладони, отправляя MotionEvent
. Если ваше приложение получает ACTION_CANCEL
, отмените жест. Если ваше приложение получает ACTION_POINTER_UP
, проверьте, установлен ли FLAG_CANCELED
. Если да, отмените жест.
Не проверяйте только FLAG_CANCELED
. В Android 13 (уровень API 33) и выше система устанавливает FLAG_CANCELED
для событий ACTION_CANCEL
, но система не устанавливает флаг в более ранних версиях Android.
Андроид 12
На Android 12 (уровень API 32) и ниже обнаружение отклонения ладони возможно только для событий касания одним указателем. Если касание ладонью является единственным указателем, система отменяет событие, устанавливая ACTION_CANCEL
для объекта события движения. Если другие указатели опущены, система устанавливает ACTION_POINTER_UP
, что недостаточно для обнаружения отклонения ладони.
Андроид 13
На Android 13 (API уровня 33) и выше, если касание ладонью является единственным указателем, система отменяет событие, устанавливая ACTION_CANCEL
и FLAG_CANCELED
на объекте события движения. Если другие указатели опущены, система устанавливает ACTION_POINTER_UP
и FLAG_CANCELED
.
Всякий раз, когда ваше приложение получает событие движения с ACTION_POINTER_UP
, проверяйте FLAG_CANCELED
, чтобы определить, указывает ли событие на отклонение ладони (или другую отмену события).
Приложения для создания заметок
ChromeOS имеет особое намерение, которое отображает зарегистрированные приложения для заметок для пользователей. Чтобы зарегистрировать приложение как приложение для заметок, добавьте следующее в манифест приложения:
<intent-filter>
<action android:name="org.chromium.arc.intent.action.CREATE_NOTE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
Когда приложение зарегистрировано в системе, пользователь может выбрать его в качестве приложения для создания заметок по умолчанию. Когда запрашивается новая заметка, приложение должно создать пустую заметку, готовую для ввода стилусом. Когда пользователь хочет аннотировать изображение (например, снимок экрана или загруженное изображение), приложение запускается с ClipData
, содержащим один или несколько элементов с URI content://
. Приложение должно создать заметку, которая использует первое прикрепленное изображение в качестве фонового изображения, и войти в режим, в котором пользователь может рисовать на экране стилусом.
Тестирование намерений делать заметки без стилуса
Чтобы проверить, правильно ли приложение реагирует на намерения создания заметок без активного стилуса, используйте следующий метод для отображения параметров создания заметок в ChromeOS:
- Перейдите в режим разработчика и сделайте устройство доступным для записи.
- Нажмите Ctrl+Alt+F2, чтобы открыть терминал.
- Выполните команду
sudo vi /etc/chrome_dev.conf
- Нажмите
i
для редактирования и добавьте--ash-enable-palette
в новую строку в конце файла. - Сохраните, нажав Esc , а затем введите : , w , q и нажмите Enter.
- Нажмите Ctrl+Alt+F1, чтобы вернуться к обычному интерфейсу ChromeOS.
- Выйдите из системы, затем войдите снова.
Меню стилуса теперь должно быть на полке:
- Нажмите кнопку стилуса на полке и выберите Новая заметка . Это должно открыть пустую заметку-рисунок.
- Сделайте снимок экрана. На полке выберите кнопку стилуса > Захват экрана или загрузите изображение. В уведомлении должна быть опция Аннотировать изображение . Это должно запустить приложение с изображением, готовым к аннотированию.
Поддержка мыши и тачпада
Большинству приложений обычно требуется обрабатывать только три крупных события, связанных с экраном: щелчок правой кнопкой мыши , наведение и перетаскивание .
Щелкните правой кнопкой мыши
Любые действия, которые заставляют приложение отображать контекстное меню, например, нажатие и удерживание элемента списка, также должны реагировать на события щелчка правой кнопкой мыши.
Для обработки событий щелчка правой кнопкой мыши приложения должны зарегистрировать View.OnContextClickListener
:
Box(modifier = Modifier.fillMaxSize()) {
AndroidView(
modifier = Modifier.fillMaxSize(),
factory = { context ->
val rootView = FrameLayout(context)
val onContextClickListener =
View.OnContextClickListener { view ->
showContextMenu()
true
}
rootView.setOnContextClickListener(onContextClickListener)
rootView
},
)
}
Подробную информацию о создании контекстных меню см. в разделе Создание контекстного меню .
Наведите курсор
Вы можете сделать макеты своих приложений более отточенными и простыми в использовании, обрабатывая события наведения. Это особенно актуально для пользовательскихкомпоненты:
Вот два наиболее распространенных примера:
- Указание пользователям, имеет ли элемент интерактивное поведение, например, может ли он быть кликабельным или редактируемым, путем изменения значка указателя мыши.
- Добавление визуальной обратной связи к элементам в большом списке или сетке при наведении на них указателя мыши
Перетащите и отпустите
В многооконном окружении пользователи ожидают возможности перетаскивания элементов между приложениями. Это справедливо как для настольных устройств, так и для планшетов, телефонов и складных устройств в режиме разделенного экрана.
Подумайте, будут ли пользователи перетаскивать элементы в ваше приложение. Например, фоторедакторы должны ожидать получения фотографий, аудиоплееры должны ожидать получения аудиофайлов, а программы для рисования должны ожидать получения фотографий.
Чтобы добавить поддержку перетаскивания, см.Перетащите и отпуститеи взгляните на запись в блоге Android на ChromeOS — Реализация Drag & Drop .
Особые соображения относительно ChromeOS
- Не забудьте запросить разрешение с помощью
requestDragAndDropPermissions()
для доступа к элементам, перетаскиваемым извне приложения. Для перетаскивания элемента в другие приложения необходимо установить флаг
View.DRAG_FLAG_GLOBAL
Расширенная поддержка указателя
Приложения, которые выполняют расширенную обработку ввода с помощью мыши и сенсорной панели, должны реализовыватьМодификатор pointerInput
для получения PointerEvent
:
@Composable private fun LogPointerEvents(filter: PointerEventType? = null) { var log by remember { mutableStateOf("") } Column { Text(log) Box( Modifier .size(100.dp) .background(Color.Red) .pointerInput(filter) { awaitPointerEventScope { while (true) { val event = awaitPointerEvent() // handle pointer event if (filter == null || event.type == filter) { log = "${event.type}, ${event.changes.first().position}" } } } } ) } }
Изучите объект PointerEvent
, чтобы определить следующее:
-
PointerType
: Мышь, стилус, сенсорный экран и т. д. изPointerEvent#changes
-
PointerEventType
: действия указателя, такие как нажатие, перемещение, прокрутка и отпускание
Игровые контроллеры
Некоторые устройства Android с большим экраном поддерживают до четырех игровых контроллеров. Используйте стандартные API игровых контроллеров Android для управления игровыми контроллерами (см. Поддержка игровых контроллеров ).
Кнопки игрового контроллера сопоставлены с общими значениями, следующими общему сопоставлению. Но не все производители игровых контроллеров следуют одним и тем же соглашениям о сопоставлении. Вы можете предоставить гораздо лучший опыт, если позволите пользователям выбирать различные популярные сопоставления контроллера. См. Обработка нажатий кнопок геймпада для получения дополнительной информации.
Режим перевода ввода
ChromeOS по умолчанию включает режим перевода ввода. Для большинства приложений Android этот режим помогает приложениям работать так, как ожидается в среде рабочего стола. Некоторые примеры включают автоматическое включение прокрутки двумя пальцами на сенсорной панели, прокрутку колесом мыши и сопоставление необработанных координат дисплея с координатами окна. Как правило, разработчикам приложений не нужно реализовывать какие-либо из этих поведений самостоятельно.
Если приложение реализует пользовательское поведение ввода, например, определяет пользовательское действие сжатия двумя пальцами на сенсорной панели, или эти преобразования ввода не обеспечивают ожидаемых приложением событий ввода, вы можете отключить режим преобразования ввода, добавив следующий тег в манифест Android:
<uses-feature
android:name="android.hardware.type.pc"
android:required="false" />