Sui dispositivi con schermi di grandi dimensioni, gli utenti spesso interagiscono con le app utilizzando una tastiera, un mouse, un trackpad, uno stilo o un gamepad. Per consentire alla tua app di accettare input da dispositivi esterni, segui questi passaggi:
- Testa il supporto di base della tastiera, ad esempio Ctrl+Z per annullare, Ctrl+C per copiare e Ctrl+S per salvare. Consulta Gestisci le azioni della tastiera per un elenco delle scorciatoie da tastiera predefinite.
- Testa il supporto avanzato della tastiera, ad esempio la navigazione da tastiera con i tasti Tab e le frecce, 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.
- Testa le interazioni di base con il mouse, tra cui il clic con il tasto destro del mouse per il menu contestuale, le modifiche alle icone al passaggio del mouse e gli eventi di scorrimento con la rotellina del mouse o il trackpad sui componenti personalizzati.
- Testa i dispositivi di input specifici per l'app, come stilo, controller di gioco e controller MIDI per app musicali.
- Prendi in considerazione il supporto di input avanzati che potrebbero far risaltare l'app negli ambienti desktop, ad esempio il touchpad come crossfader per le app per DJ, l'acquisizione del mouse per i giochi e le scorciatoie da tastiera per gli utenti che utilizzano principalmente la tastiera.
Tastiera
Il modo in cui l'app risponde all'input da tastiera contribuisce all'esperienza utente su schermi di grandi dimensioni. Esistono tre tipi di input da tastiera: navigazione, pressioni di tasti e scorciatoie.
Navigazione
La navigazione da tastiera viene implementata raramente nelle app incentrate sul tocco, ma gli utenti se l'aspettano quando utilizzano un'app e hanno le mani su una tastiera. La navigazione da tastiera può essere essenziale su smartphone, tablet, 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 componibili sono attivabili per impostazione predefinita, come un Button o un componibile con il modificatore clickable; la navigazione da tastiera dovrebbe funzionare in genere senza codice aggiuntivo. Per attivare la navigazione da tastiera per gli elementi componibili 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 saperne di più, consulta Rendere un composable attivabile.
Quando lo stato attivo è attivo, il framework Android crea una mappatura di navigazione per tutti i componenti attivabili in base alla loro posizione. In genere, questo funziona come previsto e non è necessario alcun ulteriore sviluppo.
Tuttavia, Compose non determina sempre l'elemento successivo corretto per la navigazione a schede per elementi componibili complessi come schede ed elenchi, ad esempio quando uno degli elementi componibili è un elemento scorrevole orizzontale non completamente visibile.
Per controllare il comportamento dello stato attivo, aggiungi il modificatore focusGroup al componibile principale di una raccolta di componibili. Lo stato attivo si sposta sul gruppo, poi
attraverso 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 maggiori informazioni, consulta Fornire una navigazione coerente con i focus group.
Testa l'accesso a ogni elemento UI della tua app utilizzando solo la tastiera. Gli elementi utilizzati di frequente devono essere accessibili senza input tramite 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), ad esempio per
un TextField
, le app dovrebbero comportarsi come previsto sui dispositivi con schermi di grandi dimensioni senza ulteriori interventi di sviluppo. Per le pressioni dei tasti che non possono essere previste 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 i movimenti con i tasti W, A, S e D.
Puoi gestire le singole pressioni dei tasti con il modificatore onKeyEvent, che accetta una funzione lambda chiamata quando il componente modificato riceve un evento chiave.
La proprietà KeyEvent#type ti consente di determinare se l'evento è una pressione di un tasto (KeyDown) o un rilascio di un 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 eseguire l'override del callback onKeyUp() e aggiungere il comportamento previsto per ogni codice tasto ricevuto:
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)
}
}
Un evento onKeyUp si verifica quando un tasto viene rilasciato. L'utilizzo del callback
evita che le app debbano elaborare più eventi onKeyDown se un tasto
viene tenuto premuto 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 Gestisci le azioni della tastiera.
Scorciatoie
Quando utilizzi una tastiera hardware, sono previste scorciatoie da tastiera comuni che includono i tasti Ctrl, Alt, Maiusc e Meta. Se un'app non implementa le scorciatoie, l'esperienza può risultare frustrante per gli utenti. Gli utenti esperti apprezzano anche le scorciatoie per le attività specifiche dell'app utilizzate di frequente. Le scorciatoie rendono un'app più facile da usare e la differenziano dalle app che non ne hanno.
Alcune scorciatoie comuni includono Ctrl+S (salva), Ctrl+Z (annulla) e Ctrl+Maiusc+Z (ripeti). Per un elenco delle scorciatoie predefinite, consulta Gestisci le azioni da tastiera.
Un oggetto KeyEvent ha i seguenti attributi che indicano se i tasti di modifica sono premuti:
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 per Android gestiscono gli stilo come input touchscreen. Alcuni dispositivi potrebbero anche avere una tavoletta grafica USB o Bluetooth, come Wacom Intuos. Le app per Android possono ricevere input Bluetooth, ma non input USB.
Per accedere agli oggetti dello stilo MotionEvent, 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_STYLUSoTOOL_TYPE_ERASERa seconda dello strumento che ha toccato il displayMotionEvent#getPressure()segnala la pressione fisica applicata alla stilo (se supportata)MotionEvent#getAxisValue()conMotionEvent.AXIS_TILTeMotionEvent.AXIS_ORIENTATIONforniscono l'inclinazione e l'orientamento fisici dello stilo (se supportato)
Punti storici
Android raggruppa gli eventi di input e li invia una volta per frame. Uno stilo può
segnalare eventi a frequenze molto più elevate rispetto al display. Quando crei app di disegno, controlla gli eventi che potrebbero essersi verificati nel recente passato utilizzando le API getHistorical:
MotionEvent#getHistoricalX()MotionEvent#getHistoricalY()MotionEvent#getHistoricalPressure()MotionEvent#getHistoricalAxisValue()
Palm rejection
Quando gli utenti disegnano, scrivono o interagiscono con la tua app utilizzando uno stilo, a volte
toccano lo schermo con il palmo della mano. L'evento touch (impostato su ACTION_DOWN o ACTION_POINTER_DOWN) può essere segnalato alla tua app prima che il sistema riconosca e ignori il tocco involontario del palmo.
Android annulla gli eventi touch del palmo inviando un MotionEvent. Se la tua app riceve ACTION_CANCEL, annulla il gesto. Se la tua app riceve
ACTION_POINTER_UP, controlla se FLAG_CANCELED è impostato. 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 di Android precedenti.
Android 12
Su Android 12 (livello API 32) e versioni precedenti, il rilevamento della funzionalità di palm rejection è possibile solo per gli eventi touch con un singolo puntatore. Se il tocco con il palmo è l'unico puntatore,
il sistema annulla l'evento impostando ACTION_CANCEL sull'oggetto
evento di movimento. Se altri puntatori sono in basso, il sistema imposta ACTION_POINTER_UP, che non è sufficiente 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 puntatore, il sistema annulla l'evento impostando ACTION_CANCEL e FLAG_CANCELED sull'oggetto dell'evento di movimento. Se altri puntatori 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
FLAG_CANCELED per determinare se l'evento indica il palm rejection (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 per prendere appunti, 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 viene registrata nel sistema, l'utente può selezionarla come app predefinita per prendere appunti. Quando viene richiesto un nuovo appunto, l'app deve creare un appunto vuoto pronto per l'input con lo stilo. Quando l'utente vuole annotare un'immagine (ad esempio uno screenshot o un'immagine scaricata), l'app viene avviata con ClipData contenente uno o più elementi con URI content://. L'app deve creare una nota 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.
Testa gli intent per prendere appunti senza uno stilo
Per verificare se un'app risponde correttamente agli intent di scrittura di note senza uno stilo attivo, utilizza il seguente metodo per visualizzare le opzioni di scrittura di note su ChromeOS:
- Passa alla modalità sviluppatore e rendi il dispositivo scrivibile
- Premi Ctrl+Alt+F2 per aprire un terminale.
- Esegui il comando
sudo vi /etc/chrome_dev.conf - Premi
iper modificare e aggiungi--ash-enable-palettein 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 UI di ChromeOS.
- Esci e accedi di nuovo
Ora sullo scaffale dovrebbe essere presente un menu dello stilo:
- Tocca il pulsante dello stilo sulla barra delle app e scegli Nuova nota. Dovrebbe aprirsi una nota di disegno vuota.
- Fai uno screenshot. Dalla barra delle app, seleziona pulsante dello stilo > Acquisisci schermo o scarica un'immagine. Nella notifica dovrebbe essere presente l'opzione Annota immagine. In questo modo, l'app dovrebbe avviarsi con l'immagine pronta per essere annotata.
Supporto per 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 pulsante destro del mouse
Tutte le azioni che fanno sì che un'app mostri un menu contestuale, come toccare e tenere premuto un elemento dell'elenco, devono anche reagire 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 Crea un menu contestuale.
Passaci il mouse sopra
Puoi rendere i layout della tua app più rifiniti e facili da usare gestendo gli eventi di passaggio del mouse. Questo vale in particolare per i componenti personalizzati:
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 puntatore del mouse
- Aggiunta di un feedback visivo agli elementi di un elenco o di una griglia di grandi dimensioni quando il puntatore si trova sopra di essi
Trascina
In un ambiente multi-finestra, gli utenti si aspettano di poter trascinare gli elementi tra le app. Questo vale sia per i computer che per i tablet, gli smartphone e i pieghevoli in modalità schermo diviso.
Valuta se è probabile che gli utenti trascinino elementi nella tua app. Ad esempio, gli editor di foto dovrebbero aspettarsi di ricevere foto, i lettori audio dovrebbero aspettarsi di ricevere file audio e i programmi di disegno dovrebbero aspettarsi di ricevere foto.
Per aggiungere il supporto del trascinamento, consulta Trascina e dai un'occhiata al blog post 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_GLOBALper poter essere trascinato in altre applicazioni
Supporto di puntatori avanzati
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#changesPointerEventType: azioni del puntatore, 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 standard dei controller di gioco Android per gestire i controller di gioco (consulta Supporta i controller di gioco).
I pulsanti del controller di gioco sono associati a valori comuni seguendo una mappatura comune. Tuttavia, non tutti i produttori di controller per videogiochi seguono le stesse convenzioni di mappatura. Puoi offrire un'esperienza molto migliore se consenti agli utenti di selezionare diverse mappature dei controller più diffuse. Per maggiori informazioni, consulta la pagina Elaborare pressioni dei pulsanti del gamepad.
Modalità Traduzione input
ChromeOS attiva una modalità 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 con la rotellina del mouse e la mappatura delle coordinate di visualizzazione non elaborate alle coordinate della finestra. In genere, gli sviluppatori di app non devono implementare nessuno di questi comportamenti.
Se un'app implementa un comportamento di input 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 manifest Android:
<uses-feature
android:name="android.hardware.type.pc"
android:required="false" />