Sviluppare app

Il materiale che segue è rivolto agli sviluppatori di app.

Per fare in modo che il supporto dell'app sia rotatorio, DEVI:

  1. Inserisci un FocusParkingView nel rispettivo layout delle attività.
  2. Assicurati che le viste siano (o non) attivabili.
  3. Utilizza FocusArea per aggregare tutte le visualizzazioni attivabili, ad eccezione delle FocusParkingView.

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:

  1. Tocca i tre puntini nella parte inferiore della barra degli strumenti:

    Accedi al controller rotativo emulato
    Figura 1. Accedi al controller rotativo emulato
    .
  2. Seleziona Rotazione auto nella finestra dei controlli estesi:

    Seleziona carrozzeria
    Figura 2. Seleziona Rotellina dell'auto
    .

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 o eng.
  • 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:

  1. 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 che RotaryService possa parcheggiarlo per rimuovere l'evidenziazione.
  2. Se nella finestra corrente è presente un solo FocusArea, ruotando il controller in FocusArea fa sì che RotaryService 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. Quando RotaryService 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.
  3. 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:

  1. Per aggiungere un attributo personalizzato alla tua visualizzazione. Ad esempio, per aggiungere uno stato personalizzato state_rotary_enabled alla CustomView visualizza corso, usa:
    <declare-styleable name="CustomView">
        <attr name="state_rotary_enabled" format="boolean" />
    </declare-styleable>
    
  2. 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;
    }
    
  3. 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);
    
  4. 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;
    }
    
  5. 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.
  6. 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"
    
  7. Se la visualizzazione è disattivata in qualsiasi layout, sostituisci android:enabled="false" con app:state_rotary_enabled="false", quindi aggiungi lo spazio dei nomi app, come illustrato in precedenza.
  8. Se la visualizzazione è disattivata in modo programmatico, sostituisci le chiamate a setEnabled() con chiamate a setRotaryEnabled().

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:

  1. Durante la gestione delle azioni di rotazione e sollecito, RotaryService cerca istanze di FocusArea nella gerarchia delle visualizzazioni.
  2. Quando riceve un evento di rotazione, RotaryService sposta lo stato attivo su un altro Vista che può mettere a fuoco lo stesso FocusArea.
  3. Quando ricevi un sollecito, RotaryService sposta lo stato attivo su un'altra visualizzazione che possono concentrarsi su un altro FocusArea (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 invece app: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 e app:defaultFocus (vedi sotto) nello stesso FocusArea.

FocusArea definisce anche alcuni attributi per personalizzare la navigazione rotatoria. Le aree di interesse implicite non possono essere personalizzate con questi attributi.

  1. (Android 11 QPR3, Android 11 Car, Android 12)
    Può essere utilizzato app:defaultFocus specificare l'ID di una vista discendente attivabile, che deve essere incentrata quando l'utente solleciti a questo FocusArea.
  2. (Android 11 QPR3, Android 11 Car, Android 12)
    app:defaultFocusOverridesHistory può essere impostato su true per rendere attiva la visualizzazione specificata sopra anche se con cronologia per indicare un'altra visualizzazione su cui era stata concentrata l'attenzione su FocusArea.
  3. (Android 12).
    Usa app:nudgeLeftShortcut, app:nudgeRightShortcut, app:nudgeUpShortcut e app: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 e app:nudgeShortcutDirection supportavano una sola scorciatoia di sollecito.

  4. (Android 11 QPR3, Android 11 Car, Android 12)
    Per attivare la rotazione in questo FocusArea, app:wrapAround può essere impostato su true. Viene generalmente utilizzato quando le visualizzazioni sono organizzate in cerchio oppure ovale.
  5. (Android 11 QPR3, Android 11 Car, Android 12)
    Per regolare la spaziatura interna dell'evidenziazione in questo FocusArea, usa app:highlightPaddingStart, app:highlightPaddingEnd, app:highlightPaddingTop app:highlightPaddingBottom, app:highlightPaddingHorizontal e app:highlightPaddingVertical.
  6. (Android 11 QPR3, Android 11 Car, Android 12)
    Per regolare i limiti percepiti di questo FocusArea in modo da trovare un obiettivo di sollecito, usano app:startBoundOffset, app:endBoundOffset, app:topBoundOffset, app:bottomBoundOffset, app:horizontalBoundOffset e app:verticalBoundOffset.
  7. (Android 11 QPR3, Android 11 Car, Android 12)
    Per specificare esplicitamente l'ID di un adiacenti a FocusArea (o aree) nelle indicazioni fornite, utilizza app:nudgeLeft, app:nudgeRight, app:nudgeUp e app: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:

Scorciatoia spostamento
Figura 3. Scorciatoia spostamento
.

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:

Valori predefiniti per le risorse in grassetto
Figura 4. Valori predefiniti per le risorse in grassetto
.

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:

Colore di sfondo a tinta unita
  • (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:

Stato attivo, non premuto Concentrato, premuto
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 e AXIS_VSCROLL o AXIS_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:

  1. (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 evento KEYCODE_BACK per uscire dalla modalità DM, chiamata DirectManipulationHelper.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().
  2. DEVI ascoltare gli eventi di sollecito (KEYCODE_DPAD_UP, KEYCODE_DPAD_DOWN, KEYCODE_DPAD_LEFT o KEYCODE_DPAD_RIGHT) se la visualizzazione deve gestire i solleciti.
  3. DOVRESTI ascoltare MotionEvent secondi e ricevere il numero di rotazione tra AXIS_SCROLL se la vista vuole gestire la rotazione. Puoi farlo in diversi modi:
    1. Registra un OnGenericMotionListener.
    2. Estendi la visualizzazione e sostituisci il relativo metodo dispatchTouchEvent().
  4. 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.
  5. 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'elemento ActivityView DEVONO contenere un elemento FocusParkingView come prima vista attivabile e la sua app:shouldRestoreFocus DEVE essere false.
  • I contenuti dell'elemento ActivityView non devono avere android: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 su true 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.
  • È 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 di FocusArea:
    • A tutto tondo.
    • android:focusedByDefault e app:defaultFocus
    • .
    • Obiettivi di sollecito espliciti.
    • Scorciatoie per i solleciti.
    • FocusArea senza visualizzazioni attivabili.