Il materiale che segue è rivolto agli sviluppatori di app.
Per fare in modo che il supporto dell'app sia rotatorio, DEVI:
- Inserisci un
FocusParkingView
nel rispettivo layout delle attività. - Assicurati che le viste siano (o non) attivabili.
- Utilizza
FocusArea
per aggregare tutte le visualizzazioni attivabili, ad eccezione delleFocusParkingView
.
Ognuna di queste attività viene descritta dettagliatamente di seguito, dopo aver configurato l'ambiente per sviluppare app rotative.
Configurare un controller rotativo
Per poter iniziare a sviluppare app compatibili con la rotazione, è necessario disporre di un controller rotativo o un sostituto. Le opzioni disponibili sono descritte di seguito.
Emulatore
source build/envsetup.sh && lunch car_x86_64-userdebug m -j emulator -wipe-data -no-snapshot -writable-system
Puoi anche usare aosp_car_x86_64-userdebug
.
Per accedere al controller rotativo emulato:
- Tocca i tre puntini nella parte inferiore della barra degli strumenti:
. - Seleziona Rotazione auto nella finestra dei controlli estesi:
.
Tastiera USB
- Collega una tastiera USB al tuo dispositivo con Android Automotive OS (AAOS). In alcuni casi, Ciò impedisce la visualizzazione della tastiera sullo schermo.
- Usa una build
userdebug
oeng
. - Attiva il filtro degli eventi chiave:
adb shell settings put secure android.car.ROTARY_KEY_EVENT_FILTER 1
- Per trovare la chiave corrispondente a ogni azione, consulta la tabella riportata di seguito:
Chiave Azione rotatoria D Ruota in senso antiorario E Ruota in senso orario A Spingi a sinistra D Spingi a destra W Spingi su S Spingi in basso F o virgola Pulsante centrale R oppure Esc Pulsante Indietro
Comandi ADB
Puoi utilizzare i comandi car_service
per inserire eventi di input rotatorio. Questi comandi
può essere eseguito su dispositivi con sistema operativo Android Automotive OS (AAOS) o su un emulatore.
Comandi car_service | Input rotatorio |
---|---|
adb shell cmd car_service inject-rotary |
Ruota in senso antiorario |
adb shell cmd car_service inject-rotary -c true |
Ruota in senso orario |
adb shell cmd car_service inject-rotary -dt 100 50 |
Ruota più volte in senso antiorario (100 ms fa e 50 ms fa) |
adb shell cmd car_service inject-key 282 |
Spingi a sinistra |
adb shell cmd car_service inject-key 283 |
Spingi a destra |
adb shell cmd car_service inject-key 280 |
Spingi su |
adb shell cmd car_service inject-key 281 |
Spingi in basso |
adb shell cmd car_service inject-key 23 |
Clic sul pulsante centrale |
adb shell input keyevent inject-key 4 |
Clic sul pulsante Indietro |
Controller rotativo OEM
Quando l'hardware del controller rotatorio è in funzione, si tratta della un'opzione realistica. È particolarmente utile per testare la rotazione rapida.
Visualizzazione parcheggio
FocusParkingView
è una visualizzazione trasparente nello
Libreria UI auto (car-ui-library).
RotaryService
lo utilizza per supportare la navigazione con controller rotatorio.
FocusParkingView
deve essere la prima visualizzazione attivabile
nel layout. Deve essere posizionato all'esterno di tutti i FocusArea
. Ogni finestra deve avere una
FocusParkingView
. Se stai già utilizzando il layout di base car-ui-library,
che contiene un valore FocusParkingView
, non devi aggiungerne un altro
FocusParkingView
. Di seguito è riportato un esempio di FocusParkingView
in
RotaryPlayground
.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <com.android.car.ui.FocusParkingView android:layout_width="wrap_content" android:layout_height="wrap_content"/> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"/> </FrameLayout>
Ecco i motivi per cui ti serve un FocusParkingView
:
- Android non cancella automaticamente lo stato attivo quando lo stato attivo è impostato in un'altra finestra. Se
a cancellare lo stato attivo nella finestra precedente, Android ripristina la messa a fuoco su quella finestra,
comporta lo stato attivo di due finestre contemporaneamente. Aggiunta di
FocusParkingView
a ogni finestra può risolvere il problema. Questa visualizzazione è trasparente e l'elemento attivo è evidenziato per impostazione predefinita viene disattivata, in modo che sia invisibile all'utente, indipendentemente dal fatto che lo stato sia selezionato o meno. Può mettere a fuoco in modo cheRotaryService
possa parcheggiarlo per rimuovere l'evidenziazione. - Se nella finestra corrente è presente un solo
FocusArea
, ruotando il controller inFocusArea
fa sì cheRotaryService
sposti lo stato attivo dalla vista di destra a quella di sinistra (e viceversa). Aggiunta di questa vista in corso... a ogni finestra per risolvere il problema. QuandoRotaryService
determina l'elemento attivo target èFocusParkingView
, può determinare che un wrap-around stia per si verificano nel punto in cui si evita l'effetto avvolgente non spostando lo stato attivo. - Quando il controllo rotatorio avvia un'app, Android attiva la prima vista attivabile,
che corrisponde sempre a
FocusParkingView
.FocusParkingView
determina la visualizzazione ottimale su cui concentrarsi e quindi applica l'obiettivo.
Viste attivabili
RotaryService
si basa sul framework Android
esistente
concetto di focus visivo, risalente all'epoca in cui i telefoni avevano tastiere fisiche e D-pad.
L'attributo android:nextFocusForward
esistente viene riutilizzato
(vedi Personalizzazione dell'area di messa a fuoco), ma
android:nextFocusLeft
android:nextFocusRight
android:nextFocusUp
e android:nextFocusDown
non lo sono.
RotaryService
si concentra solo sulle visualizzazioni attivabili. Alcune viste
ad esempio Button
,
sono generalmente attivabili. Altre, ad esempio TextView
e ViewGroup
,
in genere non lo sono. Le visualizzazioni selezionabili vengono attivate automaticamente, mentre le visualizzazioni vengono impostate automaticamente
cliccabili quando è disponibile
un listener di clic. Se questa logica automatica genera
non è necessario impostare in modo esplicito la attivabilità della vista. Se la logica automatica non
ottenere la messa a fuoco desiderata, imposta l'attributo android:focusable
su
true
o false
oppure imposta in modo programmatico la attivabilità della vista con
View.setFocusable(boolean)
. Affinché RotaryService
si concentri, una visualizzazione DEVE
devono soddisfare i seguenti requisiti:
- Attivabile
- Attivato
- Visibile
- Deve avere valori diversi da zero per la larghezza e l'altezza.
Se una visualizzazione non soddisfa tutti questi requisiti, ad esempio un pulsante attivabile ma disattivato,
l'utente non può usare il controllo rotatorio per concentrarsi su quest'ultimo. Se vuoi concentrarti
sulle viste disattivate,
valuta la possibilità di utilizzare uno stato personalizzato anziché android:state_enabled
per controllare il modo in cui
la visualizzazione appare senza indicare che Android deve considerarla disattivata. La tua app può fornire informazioni
il motivo per cui la visualizzazione è disattivata quando viene toccata. La sezione seguente spiega come eseguire questa operazione.
Stato personalizzato
Per aggiungere uno stato personalizzato:
- Per aggiungere un attributo personalizzato
alla tua visualizzazione. Ad esempio, per aggiungere uno stato personalizzato
state_rotary_enabled
allaCustomView
visualizza corso, usa:<declare-styleable name="CustomView"> <attr name="state_rotary_enabled" format="boolean" /> </declare-styleable>
- Per monitorare questo stato, aggiungi una variabile di istanza alla tua vista insieme ai metodi della funzione di accesso:
private boolean mRotaryEnabled; public boolean getRotaryEnabled() { return mRotaryEnabled; } public void setRotaryEnabled(boolean rotaryEnabled) { mRotaryEnabled = rotaryEnabled; }
- Per leggere il valore dell'attributo quando viene creata la vista:
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView); mRotaryEnabled = a.getBoolean(R.styleable.CustomView_state_rotary_enabled);
- Nella classe di visualizzazione, sostituisci il metodo
onCreateDrawableState()
e poi e aggiungere lo stato personalizzato, se appropriato. Ad esempio:@Override protected int[] onCreateDrawableState(int extraSpace) { if (mRotaryEnabled) extraSpace++; int[] drawableState = super.onCreateDrawableState(extraSpace); if (mRotaryEnabled) { mergeDrawableStates(drawableState, { R.attr.state_rotary_enabled }); } return drawableState; }
- Imposta il comportamento del gestore dei clic della visualizzazione in modo diverso a seconda del suo stato. Ad esempio,
gestore dei clic potrebbe non fare nulla o mostrare un avviso popup quando
mRotaryEnabled
èfalse
. - Per fare in modo che il pulsante sembri disattivato, utilizza
app:state_rotary_enabled
anzichéandroid:state_enabled
. Se non ce l'hai ancora, dovrai aggiungere:xmlns:app="http://schemas.android.com/apk/res-auto"
- Se la visualizzazione è disattivata in qualsiasi layout, sostituisci
android:enabled="false"
conapp:state_rotary_enabled="false"
, quindi aggiungi lo spazio dei nomiapp
, come illustrato in precedenza. - Se la visualizzazione è disattivata in modo programmatico, sostituisci le chiamate a
setEnabled()
con chiamate asetRotaryEnabled()
.
Area di interesse
Utilizza FocusAreas
per suddividere le viste attivabili in blocchi per effettuare la navigazione
in modo più semplice e coerente
con le altre app. Ad esempio, se l'app ha una barra degli strumenti, quest'ultima
deve essere in un FocusArea
separato dal resto dell'app. Barre delle schede e
anche gli altri elementi di navigazione devono essere separati dal resto dell'app. Elenchi di grandi dimensioni
in genere devono avere un proprio FocusArea
. In caso contrario, gli utenti devono ruotare
l'intero elenco per accedere ad alcune visualizzazioni.
FocusArea
è una sottoclasse di LinearLayout
nella libreria car-ui-library.
Se questa funzionalità è attiva, FocusArea
disegna un'evidenziazione quando uno dei suoi
discendenti. Per saperne di più, vedi
Concentrati sulla personalizzazione delle immagini in evidenza.
Durante la creazione di un blocco di navigazione nel file di layout, se intendi utilizzare un
LinearLayout
come contenitore per il blocco, usa FocusArea
.
In alternativa, aggrega il blocco in un FocusArea
.
NON nidificare una FocusArea
in un'altra FocusArea
.
Questo porta a un comportamento di navigazione indefinito. Assicurati che tutte le viste attivabili siano
nidificato all'interno di un elemento FocusArea
.
Un esempio di FocusArea
in
Il valore RotaryPlayground
è mostrato di seguito:
<com.android.car.ui.FocusArea android:layout_margin="16dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:singleLine="true"> </EditText> </com.android.car.ui.FocusArea>
FocusArea
funziona nel seguente modo:
- Durante la gestione delle azioni di rotazione e sollecito,
RotaryService
cerca istanze diFocusArea
nella gerarchia delle visualizzazioni. - Quando riceve un evento di rotazione,
RotaryService
sposta lo stato attivo su un altro Vista che può mettere a fuoco lo stessoFocusArea
. - Quando ricevi un sollecito,
RotaryService
sposta lo stato attivo su un'altra visualizzazione che possono concentrarsi su un altroFocusArea
(solitamente adiacente).
Se non includi FocusAreas
nel layout, la vista principale viene trattata
come area di interesse implicita. L'utente non può spingersi a navigare nell'app. Piuttosto,
Ruota tutte le viste attivabili, opzione che potrebbe essere appropriata per le finestre di dialogo.
Personalizzazione FocusArea
Per personalizzare la navigazione rotatoria, è possibile utilizzare due attributi View standard:
android:nextFocusForward
consente agli sviluppatori di app di specificare la rotazione in un'area di interesse. Si tratta dello stesso attributo utilizzato per controllare l'ordine di tabulazione per la navigazione da tastiera. NON utilizzare questo attributo per creare un loop. Utilizza inveceapp:wrapAround
(vedi di seguito) per creare un loop.android:focusedByDefault
consente agli sviluppatori di app di specificare visualizzazione predefinita dello stato attivo nella finestra. NON utilizzare questo attributo eapp:defaultFocus
(vedi sotto) nello stessoFocusArea
.
FocusArea
definisce anche alcuni attributi per personalizzare la navigazione rotatoria.
Le aree di interesse implicite non possono essere personalizzate con questi attributi.
- (Android 11 QPR3, Android 11 Car,
Android 12)
Può essere utilizzatoapp:defaultFocus
specificare l'ID di una vista discendente attivabile, che deve essere incentrata quando l'utente solleciti a questoFocusArea
. - (Android 11 QPR3, Android 11 Car,
Android 12)
app:defaultFocusOverridesHistory
può essere impostato sutrue
per rendere attiva la visualizzazione specificata sopra anche se con cronologia per indicare un'altra visualizzazione su cui era stata concentrata l'attenzione suFocusArea
. - (Android 12).
Usaapp:nudgeLeftShortcut
,app:nudgeRightShortcut
,app:nudgeUpShortcut
eapp:nudgeDownShortcut
per specificare l'ID di una vista discendente attivabile, che deve essere incentrata sul momento in cui l'utente spinge verso una determinata direzione. Per saperne di più, consulta il contenuto di solleciti per le scorciatoie riportate di seguito.(Android 11 QPR3, Android 11 Car, deprecato in Android 12)
app:nudgeShortcut
eapp:nudgeShortcutDirection
supportavano una sola scorciatoia di sollecito. - (Android 11 QPR3, Android 11 Car,
Android 12)
Per attivare la rotazione in questoFocusArea
,app:wrapAround
può essere impostato sutrue
. Viene generalmente utilizzato quando le visualizzazioni sono organizzate in cerchio oppure ovale. - (Android 11 QPR3, Android 11 Car,
Android 12)
Per regolare la spaziatura interna dell'evidenziazione in questoFocusArea
, usaapp:highlightPaddingStart
,app:highlightPaddingEnd
,app:highlightPaddingTop
app:highlightPaddingBottom
,app:highlightPaddingHorizontal
eapp:highlightPaddingVertical
. - (Android 11 QPR3, Android 11 Car,
Android 12)
Per regolare i limiti percepiti di questoFocusArea
in modo da trovare un obiettivo di sollecito, usanoapp:startBoundOffset
,app:endBoundOffset
,app:topBoundOffset
,app:bottomBoundOffset
,app:horizontalBoundOffset
eapp:verticalBoundOffset
. - (Android 11 QPR3, Android 11 Car,
Android 12)
Per specificare esplicitamente l'ID di un adiacenti aFocusArea
(o aree) nelle indicazioni fornite, utilizzaapp:nudgeLeft
,app:nudgeRight
,app:nudgeUp
eapp:nudgeDown
. Usa questa opzione se la ricerca geometrica è usata per impostazione predefinita non trova il target desiderato.
In genere, i movimenti consentono di spostarsi tra le aree di interesse. Con le scorciatoie di sollecito,
i solleciti a volte naviga all'interno di un FocusArea
in modo che l'utente possa aver bisogno
per sollecitare due volte a passare al FocusArea
successivo. Le scorciatoie per i solleciti sono utili
quando FocusArea
contiene un lungo elenco seguito da un
Pulsante di azione mobile,
come nell'esempio seguente:
Senza la scorciatoia di sollecito, l'utente dovrebbe ruotare l'intero elenco per raggiungere il FAB.
Imposta lo stato attivo sulla personalizzazione dei contenuti in evidenza
Come indicato in precedenza, RotaryService
si basa sul concetto esistente di Android Framework
visualizza il focus. Quando l'utente ruota e sollecita, RotaryService
sposta lo stato attivo,
mettere a fuoco un'area e rimuoverne la messa a fuoco su un'altra. In Android, quando una visualizzazione è impostata sullo stato attivo, se la visualizzazione:
- Se è stata specificata l'evidenziazione dell'elemento attivo, Android disegna l'evidenziazione corrispondente.
- Non specifica un'evidenziazione dell'elemento attivo e quella predefinita non è disattivata. Android disegna l'evidenziazione predefinita per la visualizzazione.
Le app progettate per il tocco solitamente non specificano le aree di messa a fuoco appropriate.
L'evidenziazione predefinita è fornita dal framework Android e può essere ignorata
dall'OEM. Gli sviluppatori di app la ricevono quando il tema che utilizzano deriva da
Theme.DeviceDefault
.
Per un'esperienza utente coerente, affidati all'evidenziazione predefinita dell'elemento attivo quando possibile.
Se hai bisogno di un'evidenziazione personalizzata (ad es. rotondo o a forma di pillola) o se vuoi
utilizzando un tema non derivato da Theme.DeviceDefault
, usa car-ui-library
per specificare le tue
concentrazioni in evidenza per ciascuna vista.
Per specificare un'evidenziazione personalizzata dell'elemento attivo per una visualizzazione, modifica lo sfondo o l'elemento disegnabile in primo piano della vista su un elemento drawable che differisce quando viene selezionata l'attenzione. Di solito, cambieresti sullo sfondo. Il disegno di seguito, se utilizzato come sfondo per una visualizzazione quadrata, produce un'evidenziazione arrotondata:
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_focused="true" android:state_pressed="true"> <shape android:shape="oval"> <solid android:color="@color/car_ui_rotary_focus_pressed_fill_color"/> <stroke android:width="@dimen/car_ui_rotary_focus_pressed_stroke_width" android:color="@color/car_ui_rotary_focus_pressed_stroke_color"/> </shape> </item> <item android:state_focused="true"> <shape android:shape="oval"> <solid android:color="@color/car_ui_rotary_focus_fill_color"/> <stroke android:width="@dimen/car_ui_rotary_focus_stroke_width" android:color="@color/car_ui_rotary_focus_stroke_color"/> </shape> </item> <item> <ripple...> ... </ripple> </item> </selector>
(Android 11 QPR3, Android 11 Car, Android 12) In grassetto riferimenti alle risorse nell'esempio in precedenza identificano le risorse definite dalla car-ui-library. L'OEM sostituisce queste impostazioni per garantire la coerenza con l'evidenziazione predefinita per l'elemento attivo. Ciò assicura che il colore di evidenziazione lo spessore del tratto e così via non cambiano quando l'utente passa da una visualizzazione all'altra con un stato attivo personalizzato evidenziazione e visualizzazione con l'evidenziazione predefinita. L'ultimo elemento è un'eco usata per il tocco. I valori predefiniti utilizzati per le risorse in grassetto sono i seguenti:
.Inoltre, quando a un pulsante viene assegnato un elemento pieno, viene richiesta un'evidenziazione personalizzata dell'elemento attivo. colore di sfondo per attirare l'attenzione dell'utente, come nell'esempio riportato di seguito. Questo può rendere l'evidenziazione in evidenza è difficile da vedere. In questo caso, specifica un'evidenziazione personalizzata in evidenza utilizzando colori secondari:
- (Android 11 QPR3, Android 11 Car,
Android 12)
car_ui_rotary_focus_fill_secondary_color
car_ui_rotary_focus_stroke_secondary_color
- (Android 12).
car_ui_rotary_focus_pressed_fill_secondary_color
car_ui_rotary_focus_pressed_stroke_secondary_color
Ad esempio:
Concentrato, non premuto | Concentrazione, pressione |
Scorrimento rotatorio
Se la tua app usa RecyclerView
, DOVRESTI usare
CarUiRecyclerView
. Ciò garantisce che la tua UI sia coerente
altri perché la personalizzazione di un OEM si applica a tutti i CarUiRecyclerView
.
Se gli elementi nel tuo elenco sono tutti attivabili, non devi fare altro. La navigazione rotatoria sposta lo stato attivo tra gli elementi nell'elenco e l'elenco scorre. per rendere visibile l'elemento appena selezionato.
(Android 11 QPR3, Android 11 Car,
Android 12)
Se c'è una combinazione di attivabile e non attivabile
o se non è possibile impostare lo stato attivo su tutti gli elementi, puoi attivare lo scorrimento rotatorio,
all'utente di utilizzare il controller rotatorio per scorrere gradualmente l'elenco senza saltare
elementi non attivabili. Per attivare lo scorrimento rotatorio, imposta app:rotaryScrollEnabled
a true
.
(Android 11 QPR3, Android 11 Car,
Android 12)
Puoi attivare lo scorrimento rotatorio in qualsiasi
visualizzazione scorrevole, inclusa avCarUiRecyclerView
, con
setRotaryScrollEnabled()
in CarUiUtils
. In questo caso,
devi:
- Rendi attivabile la visualizzazione scorrevole in modo che possa essere attivata quando nessuno dei suoi le viste discendenti attivabili sono visibili
- Disattiva l'evidenziazione predefinita dell'elemento attivo nella visualizzazione scorrevole chiamando
setDefaultFocusHighlightEnabled(false)
per rendere la visualizzazione scorrevole non sembra essere attivo, - Assicurati che la visualizzazione scorrevole sia attivata prima dei relativi discendenti chiamando
setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS)
. - Ascolta MotionEvents con
SOURCE_ROTARY_ENCODER
eAXIS_VSCROLL
oAXIS_HSCROLL
per indicare la distanza da scorrere e i (attraverso il cartello).
Quando lo scorrimento rotatorio è attivato su CarUiRecyclerView
e l'utente ruota
in un'area in cui non sono presenti viste attivabili, la barra di scorrimento passa da grigia a blu, come se
per indicare che la barra di scorrimento è attiva. Se vuoi, puoi implementare un effetto simile.
Gli eventi MotionEvents sono gli stessi generati dalla rotellina di scorrimento del mouse, tranne che per l'origine.
Modalità di manipolazione diretta
Solitamente, i solleciti e la rotazione consentono di spostarsi nell'interfaccia utente, mentre la pressione del pulsante centrale intervenire, anche se non è sempre così. Ad esempio, se un utente vuole regolare volume della sveglia, è possibile usare il controller rotativo per andare al cursore del volume, premere Pulsante centrale, ruota il controller per regolare il volume della sveglia, quindi premi il pulsante Indietro per tornare alla navigazione. In questo caso si parla di modalità di manipolazione diretta (DM). In questo , il controller rotatorio viene utilizzato per interagire direttamente con la vista anziché per navigare.
Implementa i messaggi diretti in due modi. Se devi gestire solo la rotazione e la visualizzazione
per manipolare le risposte a ACTION_SCROLL_FORWARD
e
ACTION_SCROLL_BACKWARD
AccessibilityEvent
in modo appropriato, utilizza
meccanismo semplice. In caso contrario, utilizza il meccanismo avanzato.
Il meccanismo semplice è l'unica opzione nelle finestre di sistema; le app possono usare entrambi i meccanismi.
Meccanismo semplice
(Android 11 QPR3, Android 11 Car,
Android 12)
L'app deve chiamare
DirectManipulationHelper.setSupportsRotateDirectly(View view, boolean enable)
.
RotaryService
riconosce quando l'utente è in modalità DM ed entra in modalità DM quando l'utente
preme il pulsante centrale mentre è attiva una visualizzazione. In modalità DM, le rotazioni vengono eseguite
ACTION_SCROLL_FORWARD
o ACTION_SCROLL_BACKWARD
ed esce dalla modalità DM
quando l'utente preme il pulsante Indietro. Il semplice meccanismo attiva/disattiva lo stato selezionato
la visualizzazione quando si entra o si esce dalla modalità DM.
Per indicare visivamente che l'utente è in modalità messaggio diretto, fai in modo che la visualizzazione appaia diversa
quando selezionato. Ad esempio, cambia lo sfondo quando
android:state_selected
è true
.
Meccanismo avanzato
L'app determina quando RotaryService
entra ed esce dalla modalità messaggio diretto. Per una distribuzione costante
esperienza utente, premendo il pulsante centrale con la visualizzazione DM con lo stato attivo si dovrebbe attivare la modalità DM.
e il pulsante Indietro dovrebbe uscire
dalla modalità DM. Se il pulsante centrale e/o il sollecito non sono utilizzati,
possono essere alternative per uscire
dalla modalità DM. Per app come Maps, un pulsante che rappresenta
È possibile utilizzare i messaggi diretti per attivare la modalità DM.
Per supportare la modalità DM avanzata, una vista:
- (Android 11 QPR3, Android 11 Car,
Android 12) DEVE ascoltare un
KEYCODE_DPAD_CENTER
per attivare la modalità DM e rimanere in ascolto di un eventoKEYCODE_BACK
per uscire dalla modalità DM, chiamataDirectManipulationHelper.enableDirectManipulationMode()
in ogni caso. Per rimanere in ascolto di questi eventi, procedi in uno dei seguenti modi:- Registra un
OnKeyListener
.
oppure
- Estendi la visualizzazione e poi sostituisci il relativo metodo
dispatchKeyEvent()
.
- Registra un
- DEVI ascoltare gli eventi di sollecito (
KEYCODE_DPAD_UP
,KEYCODE_DPAD_DOWN
,KEYCODE_DPAD_LEFT
oKEYCODE_DPAD_RIGHT
) se la visualizzazione deve gestire i solleciti. - DOVRESTI ascoltare
MotionEvent
secondi e ricevere il numero di rotazione traAXIS_SCROLL
se la vista vuole gestire la rotazione. Puoi farlo in diversi modi:- Registra un
OnGenericMotionListener
. - Estendi la visualizzazione e sostituisci il relativo metodo
dispatchTouchEvent()
.
- Registra un
- Per evitare di rimanere bloccati in modalità DM, DEVE uscire dalla modalità DM mentre la visualizzazione Frammento o Attività è attiva. a cui appartiene non è interattivo.
- DOVREBBE fornire un segnale visivo per indicare che la visualizzazione è in modalità DM.
Di seguito è riportato un esempio di visualizzazione personalizzata che utilizza la modalità DM per eseguire la panoramica e lo zoom di una mappa:
/** Whether this view is in DM mode. */ private boolean mInDirectManipulationMode;
/** Initializes the view. Called by the constructors. */ private void init() { setOnKeyListener((view, keyCode, keyEvent) -> { boolean isActionUp = keyEvent.getAction() == KeyEvent.ACTION_UP; switch (keyCode) { // Always consume KEYCODE_DPAD_CENTER and KEYCODE_BACK events. case KeyEvent.KEYCODE_DPAD_CENTER: if (!mInDirectManipulationMode && isActionUp) { mInDirectManipulationMode = true; DirectManipulationHelper.enableDirectManipulationMode(this, true); setSelected(true); // visually indicate DM mode } return true; case KeyEvent.KEYCODE_BACK: if (mInDirectManipulationMode && isActionUp) { mInDirectManipulationMode = false; DirectManipulationHelper.enableDirectManipulationMode(this, false); setSelected(false); } return true; // Consume controller nudge events only when in DM mode. // When in DM mode, nudges pan the map. case KeyEvent.KEYCODE_DPAD_UP: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(0f, -10f); return true; case KeyEvent.KEYCODE_DPAD_DOWN: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(0f, 10f); return true; case KeyEvent.KEYCODE_DPAD_LEFT: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(-10f, 0f); return true; case KeyEvent.KEYCODE_DPAD_RIGHT: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(10f, 0f); return true; // Don't consume other key events. default: return false; } });
// When in DM mode, rotation zooms the map. setOnGenericMotionListener(((view, motionEvent) -> { if (!mInDirectManipulationMode) return false; float scroll = motionEvent.getAxisValue(MotionEvent.AXIS_SCROLL); zoom(10 * scroll); return true; })); }
@Override public void onPause() { if (mInDirectManipulationMode) { // To ensure that the user doesn't get stuck in DM mode, disable DM mode // when the fragment is not interactive (e.g., a dialog shows up). mInDirectManipulationMode = false; DirectManipulationHelper.enableDirectManipulationMode(this, false); } super.onPause(); }
Puoi trovare altri esempi nel
Progetto RotaryPlayground
.
Visualizzazione attività
Quando usi una Visualizzazione attività:
ActivityView
non deve essere attivabile.- (Android 11 QPR3, Android 11 Car,
deprecato in Android 11)
I contenuti dell'elementoActivityView
DEVONO contenere un elementoFocusParkingView
come prima vista attivabile e la suaapp:shouldRestoreFocus
DEVE esserefalse
. - I contenuti dell'elemento
ActivityView
non devono avereandroid:focusByDefault
visualizzazioni.
Per l'utente, ActivityView non deve avere alcun effetto sulla navigazione, ad eccezione dell'elemento attivo
le aree non possono includere ActivityView. In altre parole, non puoi avere una singola area di interesse
presenta contenuti all'interno e all'esterno di un elemento ActivityView
. Se non aggiungi
qualsiasi FocusArea in ActivityView
, la radice della gerarchia di visualizzazione
ActivityView
è considerata un'area di interesse implicita.
Pulsanti che si attivano quando vengono premuti
La maggior parte dei pulsanti comporta un'azione quando viene selezionata. Alcuni pulsanti funzionano quando vengono premuti.
Ad esempio, i pulsanti Avanti veloce e Riavvolgi solitamente funzionano quando vengono premuti. Per rendere
i pulsanti supportano la rotazione, ascolta KEYCODE_DPAD_CENTER
KeyEvents
come segue:
mButton.setOnKeyListener((v, keyCode, event) -> { if (keyCode != KEYCODE_DPAD_CENTER) { return false; } if (event.getAction() == ACTION_DOWN) { mButton.setPressed(true); mHandler.post(mRunnable); } else { mButton.setPressed(false); mHandler.removeCallbacks(mRunnable); } return true; });
In cui mRunnable
esegue un'azione (ad esempio riavvolgi) e si programma per
vengano eseguite dopo un ritardo.
Modalità touch
Gli utenti possono utilizzare un controller rotativo per interagire con l'unità principale in un'auto in due modi: con il controller rotante o toccando lo schermo. Quando utilizzi il controller rotatorio, viene evidenziata una delle viste attivabili. Quando tocchi lo schermo, l'evidenziazione non viene evidenziata . L'utente può passare da una modalità di immissione all'altra in qualsiasi momento:
- Rotante → tocco. Quando l'utente tocca lo schermo, l'evidenziazione scompare.
- Tocco → rotatorio. Quando l'utente spinge, ruota o preme il pulsante centrale, viene visualizzata l'evidenziazione
I pulsanti Indietro e Home non influiscono sulla modalità di immissione.
Piggybacking rotatorio del concetto esistente di Android
modalità tocco.
Puoi utilizzare la modalità
View.isInTouchMode()
per determinare quale modalità di input è utilizzata dall'utente. Puoi utilizzare la modalità
OnTouchModeChangeListener
per ascoltare le modifiche. Questa opzione può essere utilizzata per personalizzare l'interfaccia utente per
modalità di input, evita cambiamenti significativi perché potrebbero sconcertare.
Risoluzione dei problemi
In un'app progettata per il tocco, capita spesso di avere visualizzazioni attivabili nidificate.
Ad esempio, potrebbe esserci un valore FrameLayout
intorno a ImageButton
,
entrambi attivabili. Questo non danneggia il tocco, ma può comportare una scarsa
esperienza utente per la rotazione perché l'utente deve ruotare due volte il controller per spostarsi
alla prossima visualizzazione interattiva. Per una buona esperienza utente, Google consiglia di effettuare:
quella esterna o quella interna attivabile, ma non entrambe.
Se un pulsante o uno switch non è più attivo quando viene premuto con il controller rotante, uno dei potrebbero verificarsi queste condizioni:
- Il pulsante o l'interruttore è stato disattivato (in breve tempo o a tempo indeterminato) a causa del
quando viene premuto. In entrambi i casi, esistono due modi per risolvere il problema:
- Lascia lo stato
android:enabled
impostato sutrue
e utilizza uno stato personalizzato per rendere non selezionabile il pulsante o il sensore, come descritto Stato personalizzato. - Usa un contenitore per circondare il pulsante o l'opzione e rendere il container attivabile anziché con il pulsante o il sensore. Il listener di clic deve trovarsi nel contenitore.
- Lascia lo stato
- È in corso la sostituzione del pulsante o del sensore. Ad esempio, l'azione intrapresa quando il pulsante
o se l'opzione viene attivata potrebbe attivare un aggiornamento delle azioni disponibili.
causando la sostituzione di pulsanti esistenti da parte di nuovi pulsanti. Ci sono due modi per risolvere questo problema:
- Anziché creare un nuovo pulsante o sensore, imposta l'icona e/o il testo del pulsante o sensore esistente.
- Come sopra, aggiungi un contenitore attivabile intorno al pulsante o all'opzione.
RotaryPlayground
RotaryPlayground
è un'app di riferimento per gli annunci rotativi. Utilizzalo per scoprire come eseguire l'integrazione
funzionalità rotative nelle tue app. RotaryPlayground
è incluso nelle build dell'emulatore e nella
build per dispositivi che eseguono Android Automotive OS (AAOS).
- Repository
RotaryPlayground
:packages/apps/Car/tests/RotaryPlayground/
- Versioni: Android 11 QPR3, Android 11 Car, e Android 12
L'app RotaryPlayground
mostra le seguenti schede a sinistra:
- Schede. Prova a navigare nelle aree di interesse, saltando gli elementi non attivabili e input di testo.
- Manipolazione diretta. Widget di test che supportano funzionalità semplici e avanzate modalità di manipolazione diretta. Questa scheda è specifica per la manipolazione diretta all'interno finestra dell'app.
- Manipolazione UI di Sys. Testare widget che supportano la manipolazione diretta nelle finestre di sistema in cui è supportata solo la modalità di manipolazione diretta.
- Griglia. Prova la navigazione rotante con pattern a z con lo scorrimento.
- Notifica. Prova ad attivare e disattivare i promemoria.
- Scorri. Prova a scorrere una combinazione di attivazioni e non attivabili contenuti.
- WebView. Prova a navigare tramite link in
WebView
. FocusArea
personalizzato. Testa la personalizzazione diFocusArea
:- A tutto tondo.
android:focusedByDefault
eapp:defaultFocus
.
- Obiettivi di sollecito espliciti.
- Scorciatoie per i solleciti.
FocusArea
senza visualizzazioni attivabili.