Na urządzeniach z dużym ekranem użytkownicy często wchodzą w interakcje z aplikacjami za pomocą klawiatury, myszy, trackpada, rysika lub pada do gier. Aby umożliwić aplikacji przyjmowanie danych wejściowych z urządzeń zewnętrznych:
- Przetestuj podstawową obsługę klawiatury, np. Ctrl+Z do cofania, Ctrl+C do kopiowania i Ctrl+S do zapisywania. Listę domyślnych skrótów klawiszowych znajdziesz w artykule Obsługa działań wykonywanych za pomocą klawiatury.
- Przetestuj zaawansowaną obsługę klawiatury, np. nawigację za pomocą klawisza Tab i strzałek, potwierdzanie wprowadzania tekstu za pomocą klawisza Enter, oraz odtwarzanie i wstrzymywanie w aplikacjach multimedialnych za pomocą spacji.
- Przetestuj podstawowe interakcje z myszą, w tym kliknięcie prawym przyciskiem myszy w celu otwarcia menu kontekstowego, zmiany ikon po najechaniu kursorem oraz zdarzenia przewijania za pomocą kółka myszy lub trackpada w komponentach niestandardowych.
- Przetestuj urządzenia wejściowe specyficzne dla aplikacji, takie jak rysik, kontrolery do gier i kontrolery MIDI w aplikacjach muzycznych.
- Rozważ obsługę zaawansowanych danych wejściowych, które mogą wyróżnić aplikację w środowiskach komputerowych, np. trackpad jako crossfader w aplikacjach dla DJ-ów, przechwytywanie myszy w grach i skróty klawiszowe dla użytkowników, którzy głównie korzystają z klawiatury.
Klawiatura
Sposób, w jaki aplikacja reaguje na dane wejściowe z klawiatury, wpływa na wygodę użytkowników korzystających z dużego ekranu. Istnieją 3 rodzaje danych wejściowych z klawiatury: nawigacja, naciśnięcia klawiszy, i skróty.
Nawigacja
Nawigacja za pomocą klawiatury jest rzadko implementowana w aplikacjach, w których główną rolę odgrywa dotyk, ale użytkownicy oczekują jej, gdy korzystają z aplikacji i mają ręce na klawiaturze. Nawigacja za pomocą klawiatury może być niezbędna na telefonach, tabletach, urządzeniach składanych i komputerach stacjonarnych dla użytkowników z potrzebami w zakresie ułatwień dostępu.
W przypadku wielu aplikacji nawigacja za pomocą strzałek i klawisza Tab jest obsługiwana
automatycznie przez platformę Android. Na przykład niektóre elementy kompozycyjne są
domyślnie możliwe do zaznaczenia, np. Button lub element kompozycyjny z
clickable. Nawigacja za pomocą klawiatury powinna działać bez
dodatkowego kodu. Aby włączyć nawigację za pomocą klawiatury w przypadku niestandardowych elementów kompozycyjnych, które nie są
domyślnie możliwe do zaznaczenia, dodaj modyfikator focusable:
var color by remember { mutableStateOf(Green) } Box( Modifier .background(color) .onFocusChanged { color = if (it.isFocused) Blue else Green } .focusable() ) { Text("Focusable 1") }
Więcej informacji znajdziesz w artykule Umożliwianie zaznaczania elementu kompozycyjnego.
Gdy zaznaczenie jest włączone, platforma Android tworzy mapowanie nawigacyjne dla wszystkich komponentów, które można zaznaczyć, na podstawie ich pozycji. Zwykle działa to zgodnie z oczekiwaniami i nie wymaga dalszego rozwoju.
Compose nie zawsze jednak określa prawidłowy następny element do nawigacji za pomocą klawisza Tab w przypadku złożonych elementów kompozycyjnych, takich jak karty i listy, np. gdy jeden z elementów kompozycyjnych jest przewijany w poziomie i nie jest w pełni widoczny.
Aby kontrolować zachowanie zaznaczenia, dodaj modyfikator focusGroup do nadrzędnego
elementu kompozycyjnego kolekcji elementów kompozycyjnych. Zaznaczenie przechodzi do grupy, a następnie przez grupę, zanim przejdzie do następnego komponentu, który można zaznaczyć, np.:
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") }
}
}
Więcej informacji znajdziesz w artykule Zapewnianie spójnej nawigacji za pomocą grup zaznaczenia.
Przetestuj dostęp do każdego elementu interfejsu aplikacji za pomocą samej klawiatury. Często używane elementy powinny być dostępne bez użycia myszy lub dotyku.
Pamiętaj, że obsługa klawiatury może być niezbędna dla użytkowników z potrzebami w zakresie ułatwień dostępu.
Naciśnięcia klawiszy
W przypadku wprowadzania tekstu, które byłoby obsługiwane przez ekranową klawiaturę wirtualną (IME),
takich jak
a TextField
, aplikacje powinny działać zgodnie z oczekiwaniami na urządzeniach z dużym ekranem bez dodatkowych
prac programistycznych. W przypadku naciśnięć klawiszy, których platforma nie może przewidzieć, aplikacje muszą samodzielnie obsługiwać zachowanie. Dotyczy to zwłaszcza aplikacji z widokami niestandardowymi.
Przykłady to aplikacje do czatowania, które używają klawisza Enter do wysyłania wiadomości, aplikacje multimedialne, które rozpoczynają i zatrzymują odtwarzanie za pomocą spacji, oraz gry które sterują ruchem za pomocą klawiszy w, a, s i d.
Poszczególne naciśnięcia klawiszy możesz obsługiwać za pomocą modyfikatora onKeyEvent, który akceptuje lambdę wywoływaną, gdy zmodyfikowany komponent otrzyma zdarzenie klawisza.
Właściwość KeyEvent#type umożliwia określenie, czy zdarzenie jest
naciśnięciem klawisza (KeyDown) czy jego zwolnieniem (KeyUp):
Box(
modifier = Modifier.focusable().onKeyEvent {
if(
it.type == KeyEventType.KeyUp &&
it.key == Key.S
) {
doSomething()
true
} else {
false
}
}
) {
Text("Press S key")
}
Możesz też zastąpić wywołanie zwrotne onKeyUp() i dodać
oczekiwane zachowanie dla każdego otrzymanego kodu klawisza:
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)
}
}
Zdarzenie onKeyUp występuje, gdy klawisz zostanie zwolniony. Użycie wywołania zwrotnego
zapobiega konieczności przetwarzania przez aplikacje wielu onKeyDown zdarzeń, jeśli klawisz
jest przytrzymywany lub zwalniany powoli. Gry i aplikacje, które muszą wykrywać moment naciśnięcia klawisza lub to, czy użytkownik przytrzymuje klawisz, mogą nasłuchiwać zdarzenia onKeyDown i samodzielnie obsługiwać powtarzające się zdarzenia onKeyDown.
Więcej informacji znajdziesz w artykule Obsługa działań wykonywanych za pomocą klawiatury.
Skróty
Podczas korzystania z klawiatury sprzętowej oczekuje się typowych skrótów klawiszowych, które obejmują klawisze Ctrl, Alt, Shift i Meta. Jeśli aplikacja nie implementuje skrótów, użytkownicy mogą być sfrustrowani. Zaawansowani użytkownicy doceniają też skróty do często używanych zadań specyficznych dla aplikacji. Skróty ułatwiają korzystanie z aplikacji i odróżniają ją od aplikacji, które nie mają skrótów.
Do typowych skrótów należą Ctrl+S (zapisz), Ctrl+Z (cofnij) i Ctrl+Shift+Z (przywróć). Listę domyślnych skrótów znajdziesz w artykule Obsługa działań wykonywanych za pomocą klawiatury.
Obiekt KeyEvent ma te atrybuty, które wskazują, czy
klawisze modyfikujące są naciśnięte:
Przykład:
Box(
Modifier.onKeyEvent {
if (it.isAltPressed && it.key == Key.A) {
println("Alt + A is pressed")
true
} else {
false
}
}
.focusable()
)
Więcej informacji znajdziesz w tych artykułach:
Rysik
Wiele urządzeń z dużym ekranem jest wyposażonych w rysik. Aplikacje na Androida obsługują rysiki jako dane wejściowe z ekranu dotykowego. Niektóre urządzenia mogą też mieć tablet graficzny USB lub Bluetooth, np. Wacom Intuos. Aplikacje na Androida mogą odbierać dane wejściowe przez Bluetooth, ale nie przez USB.
Aby uzyskać dostęp do obiektów MotionEvent rysika, dodaj modyfikator pointerInteropFilter
do powierzchni rysowania. Zaimplementuj klasę ViewModel z metodą, która
przetwarza zdarzenia ruchu. Przekaż metodę jako lambdę onTouchEvent modyfikatora
pointerInteropFilter:
@Composable
@OptIn(ExperimentalComposeUiApi::class)
fun DrawArea(modifier: Modifier = Modifier) {
Canvas(modifier = modifier
.clipToBounds()
.pointerInteropFilter {
viewModel.processMotionEvent(it)
}
) {
// Drawing code here.
}
}
Obiekt MotionEvent zawiera informacje o zdarzeniu:
MotionEvent#getToolType()zwracaTOOL_TYPE_FINGER,TOOL_TYPE_STYLUSlubTOOL_TYPE_ERASERw zależności od narzędzia, które dotknęło wyświetlacza.MotionEvent#getPressure()zgłasza fizyczny nacisk wywierany na rysik (jeśli jest obsługiwany).MotionEvent#getAxisValue()zMotionEvent.AXIS_TILTiMotionEvent.AXIS_ORIENTATIONpodaje fizyczne nachylenie i orientację rysika (jeśli są obsługiwane).
Punkty historyczne
Android grupuje zdarzenia wejściowe i dostarcza je raz na klatkę. Rysik może zgłaszać zdarzenia z dużo większą częstotliwością niż wyświetlacz. Podczas tworzenia aplikacji do rysowania sprawdzaj zdarzenia, które mogły wystąpić w niedalekiej przeszłości, za pomocą interfejsów API getHistorical:
MotionEvent#getHistoricalX()MotionEvent#getHistoricalY()MotionEvent#getHistoricalPressure()MotionEvent#getHistoricalAxisValue()
Odrzucanie dotyku dłonią
Gdy użytkownicy rysują, piszą lub wchodzą w interakcje z Twoją aplikacją za pomocą rysika, czasami dotykają ekranu dłonią. Zdarzenie dotknięcia (ustawione na
ACTION_DOWN lub ACTION_POINTER_DOWN) może zostać zgłoszone do Twojej aplikacji
zanim system rozpozna i zignoruje przypadkowy dotyk dłonią.
Android anuluje zdarzenia dotyku dłonią, wysyłając MotionEvent. Jeśli Twoja
aplikacja otrzyma ACTION_CANCEL, anuluj gest. Jeśli Twoja aplikacja otrzyma
ACTION_POINTER_UP, sprawdź, czy ustawiona jest flaga FLAG_CANCELED. Jeśli tak, anuluj gest.
Nie sprawdzaj tylko FLAG_CANCELED. W Androidzie 13 (API na poziomie 33) i nowszym system ustawia FLAG_CANCELED dla zdarzeń ACTION_CANCEL, ale w starszych wersjach Androida system nie ustawia tej flagi.
Android 12
W Androidzie 12 (API na poziomie 32) i starszym wykrywanie odrzucania dotyku dłonią jest możliwe tylko w przypadku zdarzeń dotyku jednym palcem. Jeśli dotyk dłonią jest jedynym wskaźnikiem, system anuluje zdarzenie, ustawiając ACTION_CANCEL w obiekcie zdarzenia ruchu. Jeśli inne wskaźniki są wciśnięte, system ustawia ACTION_POINTER_UP, co jest niewystarczające do wykrycia odrzucania dotyku dłonią.
Android 13
W Androidzie 13 (API na poziomie 33) i nowszym, jeśli dotyk dłonią jest jedynym wskaźnikiem, system anuluje zdarzenie, ustawiając ACTION_CANCEL i FLAG_CANCELED w obiekcie zdarzenia ruchu. Jeśli inne wskaźniki są wciśnięte, system ustawia ACTION_POINTER_UP i FLAG_CANCELED.
Za każdym razem, gdy Twoja aplikacja otrzyma zdarzenie ruchu z ACTION_POINTER_UP, sprawdź, czy ustawiona jest flaga FLAG_CANCELED, aby określić, czy zdarzenie wskazuje na odrzucenie dotyku dłonią (lub inne anulowanie zdarzenia).
Aplikacje do robienia notatek
ChromeOS ma specjalny intent, który wyświetla użytkownikom zarejestrowane aplikacje do robienia notatek. Aby zarejestrować aplikację jako aplikację do robienia notatek, dodaj do manifestu aplikacji te informacje:
<intent-filter>
<action android:name="org.chromium.arc.intent.action.CREATE_NOTE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
Gdy aplikacja jest zarejestrowana w systemie, użytkownik może wybrać ją jako domyślną aplikację do robienia notatek. Gdy zostanie poproszony o utworzenie nowej notatki, aplikacja powinna utworzyć pustą notatkę gotową do wprowadzania danych za pomocą rysika. Gdy użytkownik chce dodać adnotacje do obrazu (np. zrzutu ekranu lub pobranego obrazu), aplikacja uruchamia się z ClipData zawierającym co najmniej 1 element z identyfikatorami URI content://. Aplikacja powinna utworzyć notatkę, która używa pierwszego załączonego obrazu jako obrazu tła, i przejść do trybu, w którym użytkownik może rysować na ekranie za pomocą rysika.
Testowanie intentów do robienia notatek bez rysika
Aby sprawdzić, czy aplikacja prawidłowo reaguje na intenty do robienia notatek bez aktywnego rysika, użyj tej metody, aby wyświetlić opcje robienia notatek w ChromeOS:
- Przejdź do trybu deweloperskiego i włącz zapisywanie na urządzeniu.
- Naciśnij Ctrl+Alt+F2, aby otworzyć terminal.
- Uruchom polecenie
sudo vi /etc/chrome_dev.conf. - Naciśnij
i, aby edytować, i dodaj--ash-enable-palettedo nowego wiersza na końcu pliku. - Zapisz, naciskając Esc, a następnie wpisując :, w, q i naciskając Enter
- Naciśnij Ctrl+Alt+F1, aby wrócić do zwykłego interfejsu ChromeOS.
- Wyloguj się, a następnie zaloguj się ponownie.
Na półce powinna teraz znajdować się ikona rysika:
- Kliknij przycisk rysika na półce i wybierz Nowa notatka. Powinna się otworzyć pusta notatka do rysowania.
- Zrób zrzut ekranu. Na półce kliknij przycisk rysika > Zrzut ekranu lub pobierz obraz. W powiadomieniu powinna być opcja Dodaj adnotacje do obrazu. Powinno to spowodować uruchomienie aplikacji z obrazem gotowym do dodania adnotacji.
Obsługa myszy i touchpada
Większość aplikacji musi zwykle obsługiwać tylko 3 zdarzenia związane z dużym ekranem: kliknięcie prawym przyciskiem myszy, najechanie i przeciąganie i upuszczanie.
Kliknięcie prawym przyciskiem
Wszystkie działania, które powodują wyświetlenie przez aplikację menu kontekstowego, np. dotknięcie i przytrzymanie elementu listy, powinny też reagować na zdarzenia kliknięcia prawym przyciskiem myszy.
Aby obsługiwać zdarzenia kliknięcia prawym przyciskiem myszy, aplikacje powinny zarejestrować
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
},
)
}
Szczegółowe informacje o tworzeniu menu kontekstowych znajdziesz w artykule Tworzenie menu kontekstowego.
Najechanie
Obsługując zdarzenia najechania, możesz sprawić, że układy aplikacji będą bardziej dopracowane i łatwiejsze w użyciu. Dotyczy to zwłaszcza komponentów niestandardowych :
Oto 2 najczęstsze przykłady:
- Wskazywanie użytkownikom, czy element ma zachowanie interaktywne, np. czy można go kliknąć lub edytować, przez zmianę ikony wskaźnika myszy.
- Dodawanie wizualnych informacji zwrotnych do elementów na dużej liście lub w siatce, gdy wskaźnik znajduje się nad nimi.
Przeciągnij i upuść
W środowisku wielookienkowym użytkownicy oczekują, że będą mogli przeciągać elementy między aplikacjami. Dotyczy to zarówno komputerów stacjonarnych, jak i tabletów, telefonów i urządzeń składanych w trybie podzielonego ekranu.
Zastanów się, czy użytkownicy będą przeciągać elementy do Twojej aplikacji. Na przykład edytory zdjęć powinny oczekiwać otrzymywania zdjęć, odtwarzacze audio – plików audio, a programy do rysowania – zdjęć.
Aby dodać obsługę przeciągania, przeczytaj artykuł Przeciąganie i upuszczanie oraz post na blogu Android on ChromeOS – Implementing Drag & Drop.
Szczególne uwagi dotyczące ChromeOS
- Pamiętaj, aby poprosić o uprawnienia za pomocą
requestDragAndDropPermissions(), aby uzyskać dostęp do elementów przeciągniętych z zewnątrz aplikacji. Aby można było przeciągnąć element do innych aplikacji, musi on mieć flagę
View.DRAG_FLAG_GLOBAL.
Zaawansowana obsługa wskaźnika
Aplikacje, które zaawansowanie obsługują dane wejściowe z myszy i touchpada, powinny implementować modyfikator
pointerInput, aby uzyskać 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}" } } } } ) } }
Sprawdź obiekt PointerEvent, aby określić te informacje:
PointerType: mysz, rysik, dotyk itp. zPointerEvent#changesPointerEventType: działania wskaźnika, takie jak naciśnięcie, przesunięcie, przewinięcie i zwolnienie.
Kontrolery do gier
Niektóre urządzenia z Androidem i dużym ekranem obsługują do 4 kontrolerów do gier. Do obsługi kontrolerów do gier używaj standardowych interfejsów API kontrolerów do gier na Androida (patrz Obsługa kontrolerów do gier).
Przyciski kontrolera do gier są mapowane na typowe wartości zgodnie z typowym mapowaniem. Nie wszyscy producenci kontrolerów do gier stosują jednak te same konwencje mapowania. Możesz znacznie poprawić wygodę użytkowników, jeśli pozwolisz im wybierać różne popularne mapowania kontrolerów. Więcej informacji znajdziesz w artykule Przetwarzanie naciśnięć przycisków gamepada.
Tryb tłumaczenia danych wejściowych
ChromeOS domyślnie włącza tryb tłumaczenia danych wejściowych. W przypadku większości aplikacji na Androida ten tryb pomaga aplikacjom działać zgodnie z oczekiwaniami w środowisku komputerowym. Przykłady to automatyczne włączanie przewijania 2 palcami na touchpadzie, przewijania kółkiem myszy i mapowania surowych współrzędnych wyświetlacza na współrzędne okna. Zwykle deweloperzy aplikacji nie muszą samodzielnie implementować żadnego z tych zachowań.
Jeśli aplikacja implementuje niestandardowe zachowanie danych wejściowych, np. definiuje niestandardowe działanie uszczypnięcia 2 palcami na touchpadzie, lub te tłumaczenia danych wejściowych nie zapewniają zdarzeń wejściowych oczekiwanych przez aplikację, możesz wyłączyć tryb tłumaczenia danych wejściowych, dodając ten tag do manifestu Androida:
<uses-feature
android:name="android.hardware.type.pc"
android:required="false" />