Sui dispositivi con schermi di grandi dimensioni, gli utenti interagiscono spesso con le app utilizzando una tastiera, un mouse, un trackpad, uno stilo o una tastiera da gioco. Per consentire all'app di accettare input da dispositivi esterni:
- Testa il supporto di base della tastiera, ad esempio Ctrl+Z per annullare, Ctrl+C per copiare e Ctrl+S per salvare. Consulta Gestire le azioni da tastiera per un elenco delle scorciatoie da tastiera predefinite.
- Testa il supporto avanzato della tastiera, ad esempio il tasto Tab e la navigazione con i tasti freccia, la conferma dell'inserimento di testo con il tasto Invio e la riproduzione e la messa in pausa con la barra spaziatrice nelle app multimediali.
- Esegui test di interazioni di base con il mouse, tra cui clic con il tasto destro del mouse per il menu contestuale, modifiche delle icone al passaggio del mouse e eventi di scorrimento della rotellina del mouse o del trackpad sui componenti personalizzati.
- Testare dispositivi di input specifici per l'app, come stili, controller per videogiochi e controller MIDI per app musicali.
- Valuta la possibilità di supportare input avanzati che potrebbero far risaltare l'app negli ambienti desktop, ad esempio il touchpad come cross-fader per le app di DJ, il rilevamento del mouse per i giochi e le scorciatoie da tastiera per gli utenti che utilizzano molto la tastiera.
Tastiera
Il modo in cui la tua app risponde all'input della tastiera contribuisce all'esperienza utente sullo schermo di grandi dimensioni. Esistono tre tipi di input da tastiera: navigazione, pressioni dei tasti e scorciatoie.
Navigazione
La navigazione con tastiera viene implementata raramente nelle app incentrate sul tocco, ma gli utenti se lo aspettano quando utilizzano un'app e hanno le mani sulla tastiera. La navigazione con la tastiera può essere essenziale su smartphone, tablet, dispositivi pieghevoli e computer per gli utenti con esigenze di accessibilità.
Per molte app, la navigazione con i tasti Freccia e Tab viene gestita automaticamente dal framework Android. Ad esempio, alcuni composabili sono attivabili per impostazione predefinita, ad esempio un Button
o un composable con il modificatore clickable
. In genere, la navigazione da tastiera dovrebbe funzionare senza codice aggiuntivo. Per attivare la navigazione da tastiera per i composabili personalizzati che non sono attivabili per impostazione predefinita, aggiungi il modificatore focusable
:
var color by remember { mutableStateOf(Green) } Box( Modifier .background(color) .onFocusChanged { color = if (it.isFocused) Blue else Green } .focusable() ) { Text("Focusable 1") }
Per ulteriori informazioni, consulta Rendere un componente composable selezionabile.
Quando lo stato attivo è abilitato, il framework Android crea una mappatura di navigazione per tutti i componenti attivabili in base alla loro posizione. In genere, funziona come previsto e non sono necessari ulteriori sviluppi.
Tuttavia, Compose non determina sempre l'elemento successivo corretto per la navigazione con schede per composabili complessi come schede e elenchi, ad esempio quando uno dei composabili è scorrevole orizzontalmente e non è completamente visibile.
Per controllare il comportamento dello stato attivo, aggiungi il modificatore focusGroup
al composable principale di una raccolta di composabili. Lo stato attivo passa al gruppo, quindi
tramite il gruppo prima di passare al componente attivabile successivo, ad esempio:
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") }
}
}
Per ulteriori informazioni, vedi Offrire una navigazione coerente con i gruppi di discussione.
Testa l'accesso a ogni elemento dell'interfaccia utente della tua app utilizzando solo la tastiera. Gli elementi utilizzati frequentemente devono essere accessibili senza input del mouse o tocco.
Ricorda che il supporto della tastiera potrebbe essere essenziale per gli utenti con esigenze di accessibilità.
Sequenze di tasti
Per l'inserimento di testo che verrebbe gestito da una tastiera virtuale sullo schermo (IME), come per
un TextField
, le app dovrebbero comportarsi come previsto sui dispositivi con schermi di grandi dimensioni senza ulteriore sviluppo. Per le sequenze di tasti che non possono essere anticipate dal framework,
le app devono gestire il comportamento autonomamente. Questo è particolarmente vero per le app con visualizzazioni personalizzate.
Alcuni esempi sono le app di chat che utilizzano il tasto Invio per inviare un messaggio, le app multimediali che avviano e interrompono la riproduzione con la barra spaziatrice e i giochi che controllano il movimento con i tasti w, a, s e d.
Puoi gestire le singole battute con il modificatore onKeyEvent
, che accetta una funzione lambda chiamata quando il componente modificato riceve un evento chiave.
La proprietà KeyEvent#type
consente di determinare se l'evento è una pressione del tasto (KeyDown
) o un rilascio del tasto (KeyUp
):
Box(
modifier = Modifier.focusable().onKeyEvent {
if(
it.type == KeyEventType.KeyUp &&
it.key == Key.S
) {
doSomething()
true
} else {
false
}
}
) {
Text("Press S key")
}
In alternativa, puoi sostituire il callback onKeyUp()
e aggiungere il comportamento previsto per ogni codice chiave ricevuto:
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) } }
Un evento onKeyUp
si verifica quando viene rilasciata una chiave. L'utilizzo del callback impedisce alle app di dover elaborare più eventi onKeyDown
se un tasto viene premuto a lungo o rilasciato lentamente. I giochi e le app che devono rilevare il momento in cui viene premuto un tasto o se l'utente tiene premuto un tasto possono ascoltare l'evento onKeyDown
e gestire autonomamente gli eventi onKeyDown
ripetuti.
Per saperne di più, consulta Gestire le azioni della tastiera.
Scorciatoie
Le scorciatoie da tastiera comuni che includono i tasti Ctrl, Alt, Maiusc e Meta sono previste quando si utilizza una tastiera hardware. Se un'app non implementa le scorciatoie, l'esperienza può risultare frustrante per gli utenti. Gli utenti avanzati apprezzano anche le scorciatoie per le attività specifiche dell'app usate di frequente. Le scorciatoie semplificano l'utilizzo di un'app e la distinguono da quelle che non ne hanno.
Alcune scorciatoie comuni includono Ctrl+S (salva), Ctrl+Z (annulla) e Ctrl+Maiusc+Z (ripristina). Per un elenco delle scorciatoie predefinite, consulta Gestire le azioni da tastiera.
Un oggetto KeyEvent
ha i seguenti attributi che indicano se sono premuti i tasti modificatori:
Ad esempio:
Box(
Modifier.onKeyEvent {
if (it.isAltPressed && it.key == Key.A) {
println("Alt + A is pressed")
true
} else {
false
}
}
.focusable()
)
Per ulteriori informazioni, consulta le seguenti risorse:
Stilo
Molti dispositivi con schermo grande sono dotati di uno stilo. Le app Android gestiscono gli stili come input touchscreen. Alcuni dispositivi potrebbero avere anche una tavoletta da disegno USB o Bluetooth, come Wacom Intuos. Le app per Android possono ricevere input Bluetooth, ma non input USB.
Per accedere agli oggetti MotionEvent
dello stilo, aggiungi il modificatore pointerInteropFilter
a una superficie di disegno. Implementa una classe ViewModel
con un metodo che elabora gli eventi di movimento; passa il metodo come lambda onTouchEvent
del modificatore pointerInteropFilter
:
@Composable
@OptIn(ExperimentalComposeUiApi::class)
fun DrawArea(modifier: Modifier = Modifier) {
Canvas(modifier = modifier
.clipToBounds()
.pointerInteropFilter {
viewModel.processMotionEvent(it)
}
) {
// Drawing code here.
}
}
L'oggetto MotionEvent
contiene informazioni sull'evento:
MotionEvent#getToolType()
restituisceTOOL_TYPE_FINGER
,TOOL_TYPE_STYLUS
oTOOL_TYPE_ERASER
a seconda dello strumento che ha stabilito il contatto con il displayMotionEvent#getPressure()
indica la pressione fisica applicata al pennino (se supportato)MotionEvent#getAxisValue()
conMotionEvent.AXIS_TILT
eMotionEvent.AXIS_ORIENTATION
forniscono l'inclinazione e l'orientamento fisico dello stilo (se supportato)
Punti storici
Android raggruppa gli eventi di input e li invia una volta per frame. Uno stilo può registrare gli eventi a frequenze molto più elevate rispetto al display. Quando crei app di disegno, controlla la presenza di eventi che potrebbero risalire al passato recente utilizzando le API getHistorical
:
MotionEvent#getHistoricalX()
MotionEvent#getHistoricalY()
MotionEvent#getHistoricalPressure()
MotionEvent#getHistoricalAxisValue()
Rifiuto della palma
Quando gli utenti disegnano, scrivono o interagiscono con la tua app utilizzando uno stilo, a volte toccano lo schermo con il palmo delle mani. L'evento tocco (impostato su
ACTION_DOWN
o ACTION_POINTER_DOWN
) può essere segnalato all'app
prima che il sistema riconosca e ignori il tocco involontario con il palmo.
Android annulla gli eventi tocco con il palmo inviando un MotionEvent
. Se la tua app riceve ACTION_CANCEL
, annulla il gesto. Se la tua app riceve
ACTION_POINTER_UP
, controlla se è impostato FLAG_CANCELED
. In questo caso, annulla
il gesto.
Non controllare solo FLAG_CANCELED
. Su Android 13 (livello API 33) e versioni successive, il sistema imposta FLAG_CANCELED
per gli eventi ACTION_CANCEL
, ma non imposta il flag sulle versioni precedenti di Android.
Android 12
Su Android 12 (livello API 32) e versioni precedenti, il rilevamento del rifiuto del palmo è possibile solo per gli eventi tocco con un solo cursore. Se il tocco con il palmo è l'unico cursore,
il sistema annulla l'evento impostando ACTION_CANCEL
sull'oggetto evento movimento. Se gli altri cursori sono disattivati, il sistema imposta ACTION_POINTER_UP
, che è insufficiente per rilevare il rifiuto del palmo.
Android 13
Su Android 13 (livello API 33) e versioni successive, se il tocco con il palmo è l'unico cursore, il sistema annulla l'evento impostando ACTION_CANCEL
e FLAG_CANCELED
sull'oggetto evento di movimento. Se gli altri indicatori sono in basso, il sistema imposta
ACTION_POINTER_UP
e FLAG_CANCELED
.
Ogni volta che la tua app riceve un evento di movimento con ACTION_POINTER_UP
, controlla se è presente FLAG_CANCELED
per determinare se l'evento indica il rifiuto del palmo (o un altro annullamento dell'evento).
App per prendere appunti
ChromeOS ha un'intent speciale che mostra agli utenti le app per prendere appunti registrate. Per registrare un'app come app di note, aggiungi quanto segue al manifest dell'app:
<intent-filter>
<action android:name="org.chromium.arc.intent.action.CREATE_NOTE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
Quando un'app è registrata nel sistema, l'utente può selezionarla come app predefinita per la presa di appunti. Quando viene richiesta una nuova nota, l'app deve creare una nota vuota pronta per l'inserimento con lo stilo. Quando l'utente vuole annotare un'immagine (ad esempio uno screenshot o un'immagine scaricata), l'app si avvia con ClipData
contenente uno o più elementi con URI content://
. L'app deve creare un'annotazione che utilizzi la prima immagine allegata come immagine di sfondo e attivare una modalità in cui l'utente può disegnare sullo schermo con uno stilo.
Testare le intent di scrittura di note senza uno stilo
[TBD remove section.]
Per verificare se un'app risponde correttamente agli intent di presa di appunti senza un attivo, usa il seguente metodo per visualizzare le opzioni di presa di appunti su ChromeOS:
- Passare alla modalità sviluppatore e rendere il dispositivo scrivibile
- Premi Ctrl+Alt+F2 per aprire un terminale
- Esegui il comando
sudo vi /etc/chrome_dev.conf
- Premi
i
per modificare e aggiungere--ash-enable-palette
a una nuova riga alla fine del file - Salva premendo Esc, quindi digita :, w, q e premi Invio.
- Premi Ctrl+Alt+F1 per tornare alla normale interfaccia utente di ChromeOS
- Esci e accedi di nuovo
Sullo scaffale dovrebbe essere visualizzato un menu per lo stilo:
- Tocca il pulsante dello stilo nella sezione App e scegli Nuova nota. Dovrebbe aprirsi una nota di disegno vuota.
- Acquisisci uno screenshot. Dalla sezione, seleziona pulsante dello stilo > Acquisisci schermata o scarica un'immagine. Nella notifica dovrebbe essere presente l'opzione Aggiungi annotazioni all'immagine. L'app dovrebbe essere avviata con l'immagine pronta per essere annotata.
Supporto di mouse e touchpad
In genere, la maggior parte delle app deve gestire solo tre eventi incentrati sugli schermi di grandi dimensioni: clic con il tasto destro del mouse, passaggio del mouse e trascinamento.
Fare clic con il tasto destro del mouse
Eventuali azioni che causano la visualizzazione di un menu contestuale in un'app, ad esempio toccare e tenere premuto un elemento dell'elenco, devono reagire anche agli eventi di clic con il tasto destro del mouse.
Per gestire gli eventi di clic con il tasto destro del mouse, le app devono registrare un
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
},
)
}
Per maggiori dettagli sulla creazione di menu contestuali, vedi Creare un menu contestuale.
Passaci il mouse sopra
Puoi rendere i layout delle app più raffinati e facili da usare gestendo gli eventi di passaggio del mouse. Questo vale in particolare per i componentipersonalizzati:
I due esempi più comuni sono:
- Indicare agli utenti se un elemento ha un comportamento interattivo, ad esempio se è cliccabile o modificabile, modificando l'icona del cursore del mouse
- Aggiunta di feedback visivo agli elementi di un elenco o una griglia di grandi dimensioni quando il cursore li passa sopra
Trascina
In un ambiente con più finestre, gli utenti si aspettano di poter trascinare gli elementi tra le app. Questo vale per i computer, nonché per tablet, smartphone e dispositivi pieghevoli in modalità schermo diviso.
Valuta se è probabile che gli utenti trascinino elementi nella tua app. Ad esempio, gli editor di foto devono aspettarsi di ricevere foto, i lettori audio devono aspettarsi di ricevere file audio e i programmi di disegno devono aspettarsi di ricevere foto.
Per aggiungere il supporto del trascinamento, consulta Trascinamento e dai un'occhiata al post del blog Android su ChromeOS - Implementazione del trascinamento.
Considerazioni speciali per ChromeOS
- Ricordati di richiedere l'autorizzazione con
requestDragAndDropPermissions()
per accedere agli elementi trascinati dall'esterno dell'app Un elemento deve avere il flag
View.DRAG_FLAG_GLOBAL
per poter essere trascinato in altre applicazioniConsulta Avviare un evento di trascinamento
Supporto avanzato del cursore
Le app che gestiscono in modo avanzato l'input del mouse e del touchpad devono implementare un modificatore
pointerInput
per ottenere un 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}" } } } } ) } }
Esamina l'oggetto PointerEvent
per determinare quanto segue:
PointerType
: mouse, stilo, tocco e così via daPointerEvent#changes
PointerEventType
: azioni del cursore, come pressione, spostamento, scorrimento e rilascio
Controller di gioco
Alcuni dispositivi Android con schermo grande supportano fino a quattro controller di gioco. Utilizza le API di controller per giochi Android standard per gestire i controller per giochi (vedi Supportare i controller per giochi).
I pulsanti del controller di gioco sono mappati a valori comuni seguendo una mappatura comune. Tuttavia, non tutti i produttori di controller per giochi seguono le stesse convenzioni di mappatura. Puoi offrire un'esperienza molto migliore se consenti agli utenti di selezionare diverse mappature dei controller comuni. Per ulteriori informazioni, consulta la pagina Elaborare pressioni dei pulsanti del gamepad.
Modalità di immissione della traduzione
ChromeOS attiva una modalità di traduzione dell'input per impostazione predefinita. Per la maggior parte delle app per Android, questa modalità consente alle app di funzionare come previsto in un ambiente desktop. Alcuni esempi includono l'attivazione automatica dello scorrimento con due dita sul touchpad, lo scorrimento della rotellina del mouse e la mappatura delle coordinate del display non elaborate alle coordinate della finestra. In genere, gli sviluppatori di app non devono implementare personalmente nessuno di questi comportamenti.
Se un'app implementa un comportamento di immissione personalizzato, ad esempio definendo un'azione di pizzicamento del touchpad con due dita personalizzata, o se queste traduzioni di input non forniscono gli eventi di input previsti dall'app, puoi disattivare la modalità di traduzione di input aggiungendo il seguente tag al file Android manifest:
<uses-feature
android:name="android.hardware.type.pc"
android:required="false" />