Die folgenden Informationen richten sich an App-Entwickler.
Damit Ihre App Drehknöpfe unterstützt, MÜSSEN Sie Folgendes tun:
- Platzieren Sie ein
FocusParkingView
im jeweiligen Aktivitätslayout. - Achten Sie darauf, dass die Ansichten fokussierbar sind oder nicht.
- Verwenden Sie
FocusArea
, um alle Ansichten, die sich aufrufen lassen, mit Ausnahme derFocusParkingView
, einzurücken.
Jede dieser Aufgaben wird unten beschrieben, nachdem Sie Ihre Umgebung für die Entwicklung von Apps mit Drehknopf eingerichtet haben.
Drehregler einrichten
Bevor Sie mit der Entwicklung von Apps mit Drehknopf beginnen können, benötigen Sie entweder einen Drehknopf oder ein Ersatzgerät. Sie haben folgende Möglichkeiten:
Emulator
source build/envsetup.sh && lunch car_x86_64-userdebug m -j emulator -wipe-data -no-snapshot -writable-system
Sie können aber auch aosp_car_x86_64-userdebug
verwenden.
So greifen Sie auf den emulierten Drehregler zu:
- Tippen Sie unten in der Symbolleiste auf das Dreipunkt-Menü:
Abbildung 1 Auf emulierten Drehregler zugreifen - Wählen Sie im Fenster „Erweiterte Einstellungen“ die Option Autodrehknopf aus:
Abbildung 2 Wählen Sie „Autodrehkreuz“ aus.
USB-Tastatur
- Schließen Sie eine USB-Tastatur an Ihr Gerät an, auf dem Android Automotive OS (AAOS) ausgeführt wird. In einigen Fällen wird dadurch verhindert, dass die Bildschirmtastatur angezeigt wird.
- Verwenden Sie eine
userdebug
- odereng
-Version. - Filterung nach Schlüsselereignissen aktivieren:
adb shell settings put secure android.car.ROTARY_KEY_EVENT_FILTER 1
- In der folgenden Tabelle finden Sie den entsprechenden Schlüssel für jede Aktion:
Schlüssel Drehknopf F Gegen den Uhrzeigersinn drehen E Im Uhrzeigersinn drehen A Präzisionsausrichtung links D Präzisionsausrichtung rechts W Präzisionsausrichtung oben S Präzisionsausrichtung unten F oder Komma Mitteltaste R oder Esc Schaltfläche „Zurück“
ADB-Befehle
Mit car_service
-Befehlen können Sie Drehrad-Eingabeereignisse einschleusen. Diese Befehle können auf Geräten mit Android Automotive OS (AAOS) oder auf einem Emulator ausgeführt werden.
car_service-Befehle | Drehknopf |
---|---|
adb shell cmd car_service inject-rotary |
Gegen den Uhrzeigersinn drehen |
adb shell cmd car_service inject-rotary -c true |
Im Uhrzeigersinn drehen |
adb shell cmd car_service inject-rotary -dt 100 50 |
Mehrmals gegen den Uhrzeigersinn drehen (vor 100 ms und vor 50 ms) |
adb shell cmd car_service inject-key 282 |
Präzisionsausrichtung links |
adb shell cmd car_service inject-key 283 |
Präzisionsausrichtung rechts |
adb shell cmd car_service inject-key 280 |
Präzisionsausrichtung oben |
adb shell cmd car_service inject-key 281 |
Präzisionsausrichtung unten |
adb shell cmd car_service inject-key 23 |
Klick auf die mittlere Schaltfläche |
adb shell input keyevent inject-key 4 |
Klick auf die Schaltfläche „Zurück“ |
Drehregler des OEMs
Wenn die Hardware des Drehknopfs einsatzbereit ist, ist dies die realistischste Option. Sie eignet sich besonders für Tests mit schneller Rotation.
FocusParkingView
FocusParkingView
ist eine transparente Ansicht in der Car UI Library (car-ui-library).
RotaryService
verwendet es, um die Navigation mit dem Drehregler zu unterstützen.
FocusParkingView
muss die erste Ansicht im Layout sein, die fokussiert werden kann. Sie muss außerhalb aller FocusArea
s platziert werden. Jedes Fenster muss einen FocusParkingView
haben. Wenn Sie bereits das Basislayout der car-ui-library verwenden, das eine FocusParkingView
enthält, müssen Sie keine weitere FocusParkingView
hinzufügen. Unten sehen Sie ein Beispiel für 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>
Hier sind die Gründe, warum Sie eine FocusParkingView
benötigen:
- Unter Android wird der Fokus nicht automatisch aufgehoben, wenn er auf ein anderes Fenster gesetzt wird. Wenn Sie versuchen, den Fokus im vorherigen Fenster aufzuheben, stellt Android die Ansicht in diesem Fenster wieder scharf, sodass der Fokus auf zwei Fenster gleichzeitig gelegt wird. Dieses Problem lässt sich möglicherweise dadurch beheben, dass jedem Fenster ein
FocusParkingView
hinzugefügt wird. Diese Ansicht ist transparent und die standardmäßige Fokus-Hervorhebung ist deaktiviert. Sie ist für den Nutzer also nicht sichtbar, unabhängig davon, ob der Fokus darauf liegt oder nicht. Es kann den Fokus übernehmen, damitRotaryService
den Fokus darauf parken kann, um das Fokus-Highlight zu entfernen. - Wenn sich im aktuellen Fenster nur eine
FocusArea
befindet, bewegtRotaryService
den Fokus durch Drehen des Steuerelements in derFocusArea
von der Ansicht auf der rechten Seite zur Ansicht auf der linken Seite (und umgekehrt). Wenn Sie diese Ansicht jedem Fenster hinzufügen, kann das Problem behoben werden. WennRotaryService
feststellt, dass das Fokusziel einFocusParkingView
ist, kann es erkennen, dass ein Umlauf kurz bevorsteht. In diesem Fall wird der Umlauf vermieden, indem der Fokus nicht verschoben wird. - Wenn eine App über den Drehregler gestartet wird, legt Android den Fokus auf die erste fokussierbare Ansicht fest, also immer auf die
FocusParkingView
. DerFocusParkingView
bestimmt die optimale Ansicht, auf die der Fokus gelegt werden soll, und wendet dann den Fokus an.
Fokussierbare Ansichten
RotaryService
baut auf dem vorhandenen Konzept des Ansichtsfokus des Android-Frameworks auf, das aus der Zeit stammt, als Smartphones noch physische Tastaturen und D-Pads hatten.
Das vorhandene android:nextFocusForward
-Attribut wird für Drehknöpfe verwendet (siehe Anpassung von Fokusbereichen), android:nextFocusLeft
, android:nextFocusRight
, android:nextFocusUp
und android:nextFocusDown
jedoch nicht.
RotaryService
konzentriert sich nur auf Ansichten, die scharf gestellt werden können. Einige Ansichten, z. B. Button
, können normalerweise fokussiert werden. Andere, z. B. TextView
und ViewGroup
, sind es in der Regel nicht. Klickbare Ansichten können automatisch fokussiert werden und Ansichten sind automatisch anklickbar, wenn sie einen Klick-Listener haben. Wenn diese automatische Logik die gewünschte Fokussierbarkeit ergibt, müssen Sie die Fokussierbarkeit der Ansicht nicht explizit festlegen. Wenn die automatische Logik nicht zum gewünschten Fokus führt, legen Sie das Attribut android:focusable
auf true
oder false
fest oder legen Sie die Fokusierbarkeit der Ansicht programmatisch mit View.setFocusable(boolean)
fest. Damit RotaryService
den Fokus darauf legt, muss eine Ansicht die folgenden Anforderungen erfüllen:
- Fokussierbar
- Aktiviert
- Sichtbar
- Die Werte für „Breite“ und „Höhe“ müssen ungleich 0 sein.
Wenn eine Ansicht nicht alle diese Anforderungen erfüllt, z. B. eine Schaltfläche, die fokussiert werden kann, aber deaktiviert ist, kann der Nutzer sie nicht mit dem Drehknopf fokussieren. Wenn Sie den Fokus auf deaktivierte Ansichten legen möchten, sollten Sie statt android:state_enabled
einen benutzerdefinierten Status verwenden, um festzulegen, wie die Ansicht angezeigt wird, ohne anzugeben, dass Android sie als deaktiviert betrachten soll. Ihre App kann den Nutzer darüber informieren, warum die Ansicht deaktiviert ist, wenn er darauf tippt. Im nächsten Abschnitt wird dies erläutert.
Benutzerdefinierter Status
So fügen Sie einen benutzerdefinierten Status hinzu:
- Sie können Ihrer Ansicht ein benutzerdefiniertes Attribut hinzufügen. Wenn Sie beispielsweise der Ansichtsklasse
CustomView
einen benutzerdefinierten Statusstate_rotary_enabled
hinzufügen möchten, verwenden Sie Folgendes:<declare-styleable name="CustomView"> <attr name="state_rotary_enabled" format="boolean" /> </declare-styleable>
- Um diesen Status zu erfassen, fügen Sie Ihrer Ansicht eine Instanzvariable zusammen mit Zugriffsmethoden hinzu:
private boolean mRotaryEnabled; public boolean getRotaryEnabled() { return mRotaryEnabled; } public void setRotaryEnabled(boolean rotaryEnabled) { mRotaryEnabled = rotaryEnabled; }
- So rufen Sie den Wert Ihres Attributs beim Erstellen der Datenansicht ab:
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView); mRotaryEnabled = a.getBoolean(R.styleable.CustomView_state_rotary_enabled);
- Überschreiben Sie in Ihrer Ansichtsklasse die Methode
onCreateDrawableState()
und fügen Sie gegebenenfalls den benutzerdefinierten Status hinzu. Beispiel:@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; }
- Sie können festlegen, dass der Klick-Handler der Ansicht je nach Status unterschiedlich ausgeführt wird. Der Klick-Handler kann beispielsweise nichts tun oder ein Pop-up anzeigen, wenn
mRotaryEnabled
=false
ist. - Wenn die Schaltfläche deaktiviert erscheinen soll, verwenden Sie im Hintergrund-Zeichnenobjekt Ihrer Ansicht
app:state_rotary_enabled
anstelle vonandroid:state_enabled
. Falls noch nicht geschehen, müssen Sie Folgendes hinzufügen:xmlns:app="http://schemas.android.com/apk/res-auto"
- Wenn Ihre Ansicht in einigen Layouts deaktiviert ist, ersetzen Sie
android:enabled="false"
durchapp:state_rotary_enabled="false"
und fügen Sie dann wie oben beschrieben den Namespaceapp
hinzu. - Wenn Ihre Ansicht programmatisch deaktiviert ist, ersetzen Sie Aufrufe von
setEnabled()
durch Aufrufe vonsetRotaryEnabled()
.
FocusArea
Verwenden Sie FocusAreas
, um die fokussierbaren Ansichten in Blöcke zu unterteilen, um die Navigation zu erleichtern und für Konsistenz mit anderen Apps zu sorgen. Wenn Ihre App beispielsweise eine Symbolleiste hat, sollte diese in einer separaten FocusArea
vom Rest der App getrennt sein. Tab-Leisten und andere Navigationselemente sollten ebenfalls vom Rest der App getrennt sein. Große Listen sollten in der Regel eine eigene FocusArea
haben. Andernfalls müssen Nutzer die gesamte Liste durchgehen, um auf einige Ansichten zuzugreifen.
FocusArea
ist eine Unterklasse von LinearLayout
in der car-ui-library.
Wenn diese Funktion aktiviert ist, wird in FocusArea
ein Highlight angezeigt, wenn einer ihrer Nachkommen den Fokus hat. Weitere Informationen finden Sie unter Fokuspunkteigenschaften anpassen.
Wenn Sie beim Erstellen eines Navigationsblocks in der Layoutdatei LinearLayout
als Container für diesen Block verwenden möchten, verwenden Sie stattdessen FocusArea
.
Andernfalls setzen Sie den Block in FocusArea
.
FocusArea
darf NICHT in einem anderen FocusArea
verschachtelt sein.
Dies führt zu nicht definiertem Navigationsverhalten. Achten Sie darauf, dass alle Ansichten, die fokussiert werden können, in einem FocusArea
verschachtelt sind.
Hier ein Beispiel für eine FocusArea
in RotaryPlayground
:
<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
funktioniert so:
- Bei der Verarbeitung von Dreh- und Verschiebeaktionen sucht
RotaryService
in der Ansichtshierarchie nach Instanzen vonFocusArea
. - Wenn ein Drehereignis empfangen wird, verschiebt
RotaryService
den Fokus auf eine andere Ansicht, die den Fokus in derselbenFocusArea
übernehmen kann. - Wenn ein Nudge-Ereignis empfangen wird,
RotaryService
verschiebt der Fokus auf eine andere Ansicht, die den Fokus auf eine andere (in der Regel benachbarte)FocusArea
lenken kann.
Wenn Sie in Ihrem Layout keine FocusAreas
einfügen, wird die Stammansicht als impliziter Fokusbereich behandelt. Der Nutzer kann nicht durch Tippen durch die App navigieren. Stattdessen werden alle Ansichten, die fokussiert werden können, nacheinander angezeigt. Das ist für Dialoge möglicherweise ausreichend.
Fokusbereich anpassen
Mit zwei Standardeigenschaften für Ansichten können Sie die Drehknopfnavigation anpassen:
- Mit
android:nextFocusForward
können App-Entwickler die Reihenfolge der Drehung in einem Fokusbereich angeben. Mit diesem Attribut wird auch die Tabulatorreihenfolge für die Tastaturnavigation gesteuert. Verwenden Sie dieses Attribut NICHT, um eine Schleife zu erstellen. Verwenden Sie stattdessenapp:wrapAround
(siehe unten), um eine Schleife zu erstellen. - Mit
android:focusedByDefault
können App-Entwickler die Standardansicht für den Fokus im Fenster angeben. Verwenden Sie dieses Attribut undapp:defaultFocus
(siehe unten) NICHT im selbenFocusArea
.
FocusArea
definiert auch einige Attribute, um die Drehknopfnavigation anzupassen.
Implizite Fokusbereiche können nicht mit diesen Attributen angepasst werden.
- (Android 11 QPR3, Android 11 Auto, Android 12)
app:defaultFocus
kann verwendet werden, um die ID einer fokussierbaren untergeordneten Ansicht anzugeben, die fokussiert werden soll, wenn der Nutzer zu dieserFocusArea
wischt. - (Android 11 QPR3, Android 11 Car, Android 12)
app:defaultFocusOverridesHistory
kann auftrue
festgelegt werden, damit die oben angegebene Ansicht den Fokus erhält, auch wenn der Verlauf angibt, dass eine andere Ansicht in diesemFocusArea
den Fokus hatte. - (Android 12)
Mitapp:nudgeLeftShortcut
,app:nudgeRightShortcut
,app:nudgeUpShortcut
undapp:nudgeDownShortcut
können Sie die ID einer fokussierbaren untergeordneten Ansicht angeben, die fokussiert werden soll, wenn der Nutzer in eine bestimmte Richtung wischt. Weitere Informationen finden Sie unten im Abschnitt Tastenkürzel für Nudges.(Android 11 QPR3, Android 11 Car, in Android 12 eingestellt)
app:nudgeShortcut
undapp:nudgeShortcutDirection
unterstützten nur eine Tastenkombination für die Funktion „Nudge“. - (Android 11 QPR3, Android 11 Car, Android 12)
Wenn die Drehung in diesemFocusArea
fortgesetzt werden soll, kannapp:wrapAround
auftrue
gesetzt werden. Diese Option wird am häufigsten verwendet, wenn Ansichten in einem Kreis oder Oval angeordnet sind. - (Android 11 QPR3, Android 11 Car, Android 12)
Mitapp:highlightPaddingStart
,app:highlightPaddingEnd
,app:highlightPaddingTop
,app:highlightPaddingBottom
,app:highlightPaddingHorizontal
undapp:highlightPaddingVertical
können Sie den Abstand des Highlights in diesemFocusArea
anpassen. - (Android 11 QPR3, Android 11 Car, Android 12)
Mitapp:startBoundOffset
,app:endBoundOffset
,app:topBoundOffset
,app:bottomBoundOffset
,app:horizontalBoundOffset
undapp:verticalBoundOffset
können Sie die wahrgenommenen Grenzen diesesFocusArea
anpassen, um ein Ziel für die Aufforderung zu finden. - (Android 11 QPR3, Android 11 Car, Android 12)
Wenn Sie in den angegebenen Richtungen die ID einer benachbartenFocusArea
(oder Zonen) explizit angeben möchten, verwenden Sieapp:nudgeLeft
,app:nudgeRight
,app:nudgeUp
undapp:nudgeDown
. Verwenden Sie diese Option, wenn mit der standardmäßig verwendeten geometrischen Suche kein gewünschtes Ziel gefunden wird.
Mit dem Schieben können Sie in der Regel zwischen den Fokusbereichen wechseln. Bei Tastenkürzeln für Nudges wird manchmal zuerst innerhalb eines FocusArea
navigiert, sodass der Nutzer möglicherweise zweimal tippen muss, um zum nächsten FocusArea
zu gelangen. Tastenkürzel für Touchbedienung sind nützlich, wenn ein FocusArea
eine lange Liste enthält, gefolgt von einer Floating Action Button (Floating Action Button), wie im folgenden Beispiel:

Ohne die Tastenkürzel für die Nudge-Funktion müsste der Nutzer die gesamte Liste durchblättern, um das FAB zu erreichen.
Anpassung der Fokus-Hervorhebung
Wie bereits erwähnt, basiert RotaryService
auf dem vorhandenen Konzept des Android-Frameworks für den Ansichtsfokus. Wenn der Nutzer das Bild dreht und verschiebt, bewegt RotaryService
den Fokus, sodass eine Ansicht fokussiert und eine andere defokussiert wird. Wenn auf Android-Geräten der Fokus auf einer Ansicht liegt, gilt Folgendes:
- Sie haben ein eigenes Fokus-Highlight angegeben. Android zeichnet das Fokus-Highlight der Ansicht.
- Wenn keine Fokus-Hervorhebung angegeben ist und die Standard-Fokus-Hervorhebung nicht deaktiviert ist, zeichnet Android die Standard-Fokus-Hervorhebung für die Ansicht.
Bei Apps, die für die Bedienung per Berührung entwickelt wurden, werden in der Regel keine geeigneten Fokuspunkte angegeben.
Das standardmäßige Fokus-Highlight wird vom Android-Framework bereitgestellt und kann vom OEM überschrieben werden. App-Entwickler erhalten sie, wenn das von ihnen verwendete Design von Theme.DeviceDefault
abgeleitet ist.
Verwenden Sie nach Möglichkeit die standardmäßige Fokus-Hervorhebung, um für eine einheitliche Nutzererfahrung zu sorgen.
Wenn Sie einen benutzerdefinierten Fokusbereich (z. B. rund oder oval) benötigen oder ein nicht von Theme.DeviceDefault
abgeleitetes Design verwenden, können Sie mit den Ressourcen der car-ui-library für jede Ansicht einen eigenen Fokusbereich festlegen.
Wenn Sie für eine Ansicht ein benutzerdefiniertes Fokus-Highlight angeben möchten, ändern Sie das Hintergrund- oder Vordergrund-Drawable der Ansicht in ein Drawable, das sich unterscheidet, wenn die Ansicht im Fokus ist. Normalerweise ändern Sie den Hintergrund. Wenn das folgende drawable als Hintergrund für eine quadratische Ansicht verwendet wird, wird ein runder Fokus hervorgehoben:
<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 Auto, Android 12) Fett formatierte Ressourcenreferenzen im Beispiel oben geben Ressourcen an, die von der car-ui-library definiert wurden. Der OEM überschreibt diese, damit sie mit der von ihm angegebenen Standard-Akzentuierung übereinstimmen. So ändern sich die Farbe des Fokus-Akzent, die Strichbreite usw. nicht, wenn der Nutzer zwischen einer Ansicht mit einem benutzerdefinierten Fokus-Akzent und einer Ansicht mit dem standardmäßigen Fokus-Akzent wechselt. Das letzte Element ist eine Welle, die für Berührungen verwendet wird. Die Standardwerte für die fett formatierten Ressourcen sehen so aus:

Außerdem ist ein benutzerdefiniertes Fokus-Highlight erforderlich, wenn einer Schaltfläche eine durchgehende Hintergrundfarbe zugewiesen wird, um die Aufmerksamkeit der Nutzer darauf zu lenken, wie im Beispiel unten. Dadurch kann es sein, dass der Fokusbereich nur schwer zu erkennen ist. Geben Sie in diesem Fall ein benutzerdefiniertes Fokus-Highlight mit sekundären Farben an:
![]() |
- (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
Beispiel:
![]() |
![]() |
|
Fokussiert, nicht gedrückt | Konzentriert, gedrückt |
Drehknopf zum Scrollen
Wenn Ihre App RecyclerView
verwendet, sollten Sie stattdessen CarUiRecyclerView
verwenden. So ist Ihre Benutzeroberfläche einheitlich, da die Anpassung eines OEMs auf alle CarUiRecyclerView
s angewendet wird.
Wenn alle Elemente in Ihrer Liste fokussierbar sind, müssen Sie nichts weiter tun. Bei der Drehknopfnavigation wird der Fokus durch die Elemente in der Liste verschoben und die Liste scrollt, um das neu fokussierte Element sichtbar zu machen.
(Android 11 QPR3, Android 11 Auto, Android 12)
Wenn sich Elemente, die fokussiert werden können, und solche, die nicht fokussiert werden können, mischen oder wenn sich alle Elemente nicht fokussieren lassen, können Sie das Drehknopf-Scrollen aktivieren. So kann der Nutzer mit dem Drehknopf nach und nach durch die Liste scrollen, ohne Elemente zu überspringen, die sich nicht fokussieren lassen. Wenn Sie das Drehen zum Scrollen aktivieren möchten, setzen Sie das Attribut app:rotaryScrollEnabled
auf true
.
(Android 11 QPR3, Android 11 Auto, Android 12)
Du kannst das Drehen zum Scrollen in jeder scrollbaren Ansicht, einschließlich avCarUiRecyclerView
, mit der Methode setRotaryScrollEnabled()
in CarUiUtils
aktivieren. Gehen Sie dazu so vor:
- Die scrollbare Ansicht so gestalten, dass sie fokussiert werden kann, wenn keine ihrer fokussierbaren untergeordneten Ansichten sichtbar sind,
- Deaktivieren Sie die standardmäßige Fokus-Hervorhebung in der scrollbaren Ansicht, indem Sie
setDefaultFocusHighlightEnabled(false)
aufrufen, damit die scrollbare Ansicht nicht den Anschein erweckt, dass der Fokus darauf liegt. - Rufen Sie
setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS)
auf, damit die scrollbare Ansicht vor ihren untergeordneten Elementen fokussiert wird. - Hören Sie auf MotionEvents mit
SOURCE_ROTARY_ENCODER
und entwederAXIS_VSCROLL
oderAXIS_HSCROLL
, um die zu scrollende Entfernung und die Richtung (durch das Schild) anzugeben.
Wenn das Drehen zum Scrollen auf einem CarUiRecyclerView
aktiviert ist und der Nutzer den Bildschirm in einen Bereich dreht, in dem keine fokussierbaren Ansichten vorhanden sind, ändert sich die Scrollleiste von grau zu blau, um anzuzeigen, dass die Scrollleiste fokussiert ist. Sie können einen ähnlichen Effekt implementieren, wenn Sie möchten.
Die MotionEvents sind mit denen identisch, die von einem Mausrad generiert werden, mit Ausnahme der Quelle.
Modus für direkte Manipulation
Normalerweise werden mit Wippen und Drehen die verschiedenen Bereiche der Benutzeroberfläche aufgerufen, während durch Drücken der mittleren Schaltfläche eine Aktion ausgeführt wird. Das ist jedoch nicht immer der Fall. Wenn ein Nutzer beispielsweise die Wecklautstärke anpassen möchte, kann er mit dem Drehknopf zum Schieberegler für die Lautstärke gehen, die mittlere Taste drücken, den Drehknopf drehen, um die Wecklautstärke anzupassen, und dann die Schaltfläche „Zurück“ drücken, um zur Navigation zurückzukehren. Dies wird als Direkte Manipulation (DM) bezeichnet. In diesem Modus wird der Drehregler nicht zum Navigieren, sondern zum direkten Interagieren mit der Ansicht verwendet.
Sie haben zwei Möglichkeiten, DM zu implementieren. Wenn Sie nur die Drehung verarbeiten müssen und die Ansicht, die Sie bearbeiten möchten, auf ACTION_SCROLL_FORWARD
- und ACTION_SCROLL_BACKWARD
-AccessibilityEvent
s reagiert, verwenden Sie den einfachen Mechanismus. Andernfalls verwenden Sie den erweiterten Mechanismus.
Der einfache Mechanismus ist die einzige Option in Systemfenstern. Apps können beide Mechanismen verwenden.
Einfacher Mechanismus
(Android 11 QPR3, Android 11 Car, Android 12)
Ihre App sollte DirectManipulationHelper.setSupportsRotateDirectly(View view, boolean enable)
aufrufen.
RotaryService
erkennt, wenn sich der Nutzer im DM-Modus befindet, und wechselt in den DM-Modus, wenn der Nutzer die Schaltfläche „Zur Mitte“ drückt, während eine Ansicht fokussiert ist. Im DM-Modus werden Drehungen mit ACTION_SCROLL_FORWARD
oder ACTION_SCROLL_BACKWARD
ausgeführt und der DM-Modus wird beendet, wenn der Nutzer auf die Schaltfläche „Zurück“ drückt. Der einfache Mechanismus wechselt den ausgewählten Status der Ansicht, wenn der DM-Modus aktiviert oder deaktiviert wird.
Um Nutzern visuell zu signalisieren, dass sie sich im DM-Modus befinden, sollte die Ansicht bei Auswahl anders aussehen. Ändern Sie beispielsweise den Hintergrund, wenn android:state_selected
= true
ist.
Erweiterter Mechanismus
Die App bestimmt, wann RotaryService
in den DM-Modus wechselt und ihn wieder verlässt. Für eine einheitliche Nutzererfahrung sollte durch Drücken der Mitteltaste bei fokussierter Direktnachrichtenansicht der Direktnachrichtenmodus aktiviert und durch Drücken der Schaltfläche „Zurück“ der Direktnachrichtenmodus beendet werden. Wenn die Mitteltaste und/oder die Verschiebung nicht verwendet werden, können sie auch als alternative Möglichkeiten dienen, den DM-Modus zu beenden. In Apps wie Google Maps kann eine Schaltfläche für Direktnachrichten verwendet werden, um den Direktnachrichtenmodus aufzurufen.
Damit der erweiterte DM-Modus unterstützt wird, muss eine Datenansicht:
- (Android 11 QPR3, Android 11 Car, Android 12) MUSS auf ein
KEYCODE_DPAD_CENTER
-Ereignis warten, um in den DM-Modus zu wechseln, und auf einKEYCODE_BACK
-Ereignis, um den DM-Modus zu beenden, und in jedem FallDirectManipulationHelper.enableDirectManipulationMode()
aufrufen. So können Sie auf diese Ereignisse warten:OnKeyListener
registrieren
oder
- Maximieren Sie die Ansicht und überschreiben Sie dann die
dispatchKeyEvent()
-Methode.
- SOLLTE auf Nudge-Ereignisse (
KEYCODE_DPAD_UP
,KEYCODE_DPAD_DOWN
,KEYCODE_DPAD_LEFT
oderKEYCODE_DPAD_RIGHT
) achten, wenn die Ansicht Nudges verarbeiten soll. - MÜSSEN
MotionEvent
s überwachen und die Anzahl der Drehungen inAXIS_SCROLL
abrufen, wenn die Ansicht die Drehung verarbeiten soll. Dafür gibt es mehrere Möglichkeiten:OnGenericMotionListener
registrieren- Maximieren Sie die Ansicht und überschreiben Sie die
dispatchTouchEvent()
-Methode.
- Um zu vermeiden, dass Sie im DM-Modus stecken bleiben, müssen Sie den DM-Modus beenden, wenn das Fragment oder die Aktivität, zu der die Ansicht gehört, nicht interaktiv ist.
- Es sollte eine visuelle Kennzeichnung geben, die darauf hinweist, dass sich die Ansicht im DM-Modus befindet.
Unten sehen Sie ein Beispiel für eine benutzerdefinierte Ansicht, in der der DM-Modus zum Schwenken und Zoomen einer Karte verwendet wird:
/** 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(); }
Weitere Beispiele finden Sie im Projekt RotaryPlayground
.
ActivityView
Bei Verwendung einer Aktivitätsanzeige gilt Folgendes:
- Der
ActivityView
sollte nicht fokussierbar sein. - (Android 11 QPR3, Android 11 Auto, ��
ActivityView
FocusParkingView
app:shouldRestoreFocus
false
- Die Inhalte der
ActivityView
dürfen keineandroid:focusByDefault
Aufrufe haben.
Für den Nutzer sollten Aktivitätsansichten keine Auswirkungen auf die Navigation haben, mit Ausnahme der Tatsache, dass Fokusbereiche keine Aktivitätsansichten umfassen können. Mit anderen Worten: Sie können keinen einzelnen Fokusbereich haben, der Inhalte innerhalb und außerhalb einer ActivityView
enthält. Wenn Sie Ihrem ActivityView
keine Fokusbereiche hinzufügen, wird der Stamm der Ansichtshierarchie im ActivityView
als impliziter Fokusbereich betrachtet.
Tasten, die durch Drücken aktiviert werden
Die meisten Schaltflächen lösen beim Klicken eine Aktion aus. Einige Tasten funktionieren stattdessen, wenn sie gedrückt gehalten werden.
Die Tasten „Vor“ und „Zurück“ funktionieren beispielsweise in der Regel, wenn sie gedrückt gehalten werden. Wenn Sie solche Schaltflächen für den Drehknopf unterstützen möchten, gehen Sie so vor:KEYCODE_DPAD_CENTER
KeyEvents
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; });
Dabei führt mRunnable
eine Aktion aus (z. B. Zurückspulen) und wird nach einer Verzögerung ausgeführt.
Touch-Modus
Nutzer können mit einem Drehregler auf zwei Arten mit der Headunit in einem Auto interagieren: entweder über den Drehregler oder durch Berühren des Bildschirms. Wenn Sie den Drehregler verwenden, wird eine der Ansichten, die fokussiert werden können, hervorgehoben. Wenn Sie den Bildschirm berühren, wird kein Fokus-Highlight angezeigt. Der Nutzer kann jederzeit zwischen diesen Eingabemodi wechseln:
- Drehschalter → Touchbedienung Wenn der Nutzer den Bildschirm berührt, verschwindet die Fokusmarkierung.
- Touch → Drehknopf Wenn der Nutzer die mittlere Taste drückt, dreht oder antippt, wird die Fokusmarkierung angezeigt.
Die Schaltflächen „Zurück“ und „Startseite“ haben keine Auswirkungen auf den Eingabemodus.
Der Drehknopf nutzt das vorhandene Konzept des Touch-Modus von Android.
Mit View.isInTouchMode()
können Sie ermitteln, welchen Eingabemodus der Nutzer verwendet. Mit OnTouchModeChangeListener
kannst du auf Änderungen warten. Sie können die Benutzeroberfläche zwar für den aktuellen Eingabemodus anpassen, aber größere Änderungen sollten Sie vermeiden, da sie verwirrend sein können.
Fehlerbehebung
In einer App, die für Touchbedienung entwickelt wurde, sind verschachtelte Ansichten mit Fokus üblich.
Beispiel: Ein FrameLayout
umgibt ein ImageButton
, auf die beide der Fokus gelegt werden kann. Das ist für Touchbedienung kein Problem, kann aber zu einer schlechten Nutzererfahrung bei Drehknöpfen führen, da der Nutzer den Controller zweimal drehen muss, um zur nächsten interaktiven Ansicht zu gelangen. Für eine gute Nutzererfahrung empfiehlt Google, entweder die äußere Ansicht oder die innere Ansicht fokussierbar zu machen, aber nicht beides.
Wenn eine Taste oder ein Schalter den Fokus verliert, wenn er über den Drehregler gedrückt wird, kann eine der folgenden Bedingungen vorliegen:
- Die Taste oder der Schalter wird (kurzzeitig oder dauerhaft) deaktiviert, weil die Taste gedrückt wird. In beiden Fällen gibt es zwei Möglichkeiten, das Problem zu beheben:
- Lassen Sie den Status „
android:enabled
“ als „true
“ und verwenden Sie einen benutzerdefinierten Status, um die Schaltfläche oder den Schalter wie unter Benutzerdefinierter Status beschrieben auszugrauen. - Verwenden Sie einen Container, um die Schaltfläche oder den Schalter zu umschließen, und legen Sie fest, dass der Container statt der Schaltfläche oder des Schalters den Fokus erhält. Der Klick-Listener muss sich im Container befinden.
- Lassen Sie den Status „
- Die Taste oder der Schalter wird ersetzt. Beispielsweise kann die Aktion, die ausgeführt wird, wenn die Schaltfläche gedrückt oder der Schalter umgeschaltet wird, ein Aktualisieren der verfügbaren Aktionen auslösen, wodurch vorhandene Schaltflächen durch neue ersetzt werden. Dafür gibt es zwei Möglichkeiten:
- Anstatt eine neue Schaltfläche oder einen neuen Schalter zu erstellen, können Sie das Symbol und/oder den Text der vorhandenen Schaltfläche oder des vorhandenen Schalters festlegen.
- Fügen Sie wie oben beschrieben einen Container um die Schaltfläche oder den Schalter herum hinzu, der den Fokus aufnehmen kann.
RotaryPlayground
RotaryPlayground
ist eine Referenz-App für Drehknopf. Hier erfahren Sie, wie Sie Drehfunktionen in Ihre Apps einbinden. RotaryPlayground
ist in Emulator-Builds und Builds für Geräte mit Android Automotive OS (AAOS) enthalten.
RotaryPlayground
-Repository:packages/apps/Car/tests/RotaryPlayground/
- Versionen: Android 11 QPR3, Android 11 Car und Android 12
In der RotaryPlayground
App werden links die folgenden Tabs angezeigt:
- Karten Testen Sie die Navigation zwischen Fokusbereichen und überspringen Sie Elemente, die nicht fokussiert werden können, sowie Texteingaben.
- Direkte Manipulation Testen Sie Widgets, die den einfachen und erweiterten Modus für die direkte Manipulation unterstützen. Dieser Tab dient speziell zur direkten Bearbeitung im App-Fenster.
- Manipulation der System-UI Testen Sie Widgets, die die direkte Manipulation unterstützen, in Systemfenstern, in denen nur der einfache Modus für die direkte Manipulation unterstützt wird.
- Raster Testen Sie die Z‑Muster-Drehnavigation mit Scrollen.
- Benachrichtigung Testen Sie, ob Sie Vorabbenachrichtigungen durch Tippen auf das Display ein- und ausblenden können.
- Scrollen Testen Sie das Scrollen durch eine Mischung aus Inhalten, die sich aufrufen lassen, und solchen, die nicht aufrufbar sind.
- WebView Testen Sie die Navigation über Links in einer
WebView
. - Benutzerdefiniert
FocusArea
Anpassung vonFocusArea
testen:- Umbruch
android:focusedByDefault
undapp:defaultFocus
.
- Explizite Ziele für Nudges
- Tastenkürzel für das Anstupsen
FocusArea
ohne fokussierbare Ansichten.