Poniższy materiał jest przeznaczony dla deweloperów aplikacji.
Aby aplikacja obsługiwała sterowanie obrotowe, MUSISZ:
- Umieść
FocusParkingView
w odpowiednim układzie aktywności. - Upewnij się, że widoki są (lub nie są) możliwe do skupienia.
- Użyj
FocusArea
, aby objąć wszystkie widoki, które można skupić, z wyjątkiem widokuFocusParkingView
.
Po skonfigurowaniu środowiska do tworzenia aplikacji obsługujących sterowanie obrotowe możesz wykonywać poszczególne zadania opisane poniżej.
Konfigurowanie kontrolera obrotowego
Zanim zaczniesz tworzyć aplikacje obsługujące sterowanie za pomocą pokrętła, musisz mieć kontroler obrotowy lub urządzenie zastępcze. Do wyboru masz opcje opisane poniżej.
Emulator
source build/envsetup.sh && lunch car_x86_64-userdebug m -j emulator -wipe-data -no-snapshot -writable-system
Możesz też użyć aosp_car_x86_64-userdebug
.
Aby uzyskać dostęp do emulowanego sterownika obrotowego:
- Kliknij 3 kropki u dołu paska narzędzi:
Rysunek 1. Dostęp do emulowanego kontrolera obrotowego - W oknie rozszerzonych ustawień wybierz Gałka sterująca:
Rysunek 2. Wybierz Car rotary
Klawiatura USB
- Podłącz klawiaturę USB do urządzenia z Androidem Automotive (AAOS). W niektórych przypadkach uniemożliwi to wyświetlanie klawiatury ekranowej.
- Użyj wersji
userdebug
lubeng
. - Włącz filtrowanie kluczowych zdarzeń:
adb shell settings put secure android.car.ROTARY_KEY_EVENT_FILTER 1
- W tabeli poniżej znajdziesz odpowiedni klucz dla każdego działania:
Klucz Działanie obrotowe P Obróć w lewo E Obróć w prawo A Posuń w lewo D Posuń w prawo W Posuń w górę S Posuń w dół F lub przecinek Przycisk środkowy R lub Esc Przycisk Wstecz
Polecenia ADB
Do wstawiania zdarzeń sterowania obrotowego możesz używać poleceń car_service
. Te polecenia można wykonywać na urządzeniach z systemem operacyjnym Android Automotive (AAOS) lub w emulatorze.
polecenia car_service. | Pokrętło |
---|---|
adb shell cmd car_service inject-rotary |
Obróć w lewo |
adb shell cmd car_service inject-rotary -c true |
Obróć w prawo |
adb shell cmd car_service inject-rotary -dt 100 50 |
Obróć w lewo kilka razy (100 ms temu i 50 ms temu) |
adb shell cmd car_service inject-key 282 |
Posuń w lewo |
adb shell cmd car_service inject-key 283 |
Posuń w prawo |
adb shell cmd car_service inject-key 280 |
Posuń w górę |
adb shell cmd car_service inject-key 281 |
Posuń w dół |
adb shell cmd car_service inject-key 23 |
Kliknięcie środkowego przycisku |
adb shell input keyevent inject-key 4 |
Kliknięcie przycisku Wstecz |
OEM kontroler obrotowy
Gdy sterownik obrotowy jest gotowy do użycia, jest to najbardziej prawdopodobna opcja. Jest to szczególnie przydatne podczas testowania szybkiej rotacji.
FocusParkingView
FocusParkingView
to przezroczysty widok w bibliotece Car UI (car-ui-library).
RotaryService
używa go do obsługi sterowania za pomocą kontrolera obrotowego.
FocusParkingView
musi być pierwszym widokiem, na którym można ustawić fokus w układzie. Musi być umieszczony poza wszystkimi FocusArea
. Każde okno musi mieć jeden FocusParkingView
. Jeśli używasz już szablonu bazowego z biblioteki car-ui-library, który zawiera element FocusParkingView
, nie musisz dodawać kolejnego elementu FocusParkingView
. Poniżej znajdziesz przykład FocusParkingView
w 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>
Oto powody, dla których potrzebujesz FocusParkingView
:
- Android nie powoduje automatycznego usunięcia fokusa, gdy jest on ustawiony w innym oknie. Jeśli spróbujesz usunąć fokus z poprzedniego okna, Android ponownie skoncentruje widok w tym oknie, co spowoduje, że 2 okna będą jednocześnie w fokusie. Dodanie
FocusParkingView
do każdego okna może rozwiązać ten problem. Ten widok jest przezroczysty, a domyślne wyróżnienie zaznaczenia jest wyłączone, więc jest niewidoczny dla użytkownika niezależnie od tego, czy jest zaznaczony, czy nie. Możesz skupić się naRotaryService
, aby zablokować na nim ostrość lub usunąć wyróżnienie ostrości. - Jeśli w bieżącym oknie jest tylko 1
FocusArea
, obrócenie kontrolera wFocusArea
spowoduje, żeRotaryService
przeniesie fokus z widoku po prawej na widok po lewej (i odwrotnie). Dodanie tego widoku do każdego okna może rozwiązać problem. GdyRotaryService
określi, że element docelowy fokusu toFocusParkingView
, może stwierdzić, że za chwilę nastąpi zawijanie, i uniknąć tego, nie przenosząc fokusu. - Gdy pokrętło uruchamia aplikację, Android ustawia fokus na pierwszym widoku, który można zaznaczyć, czyli zawsze na
FocusParkingView
. FunkcjaFocusParkingView
określa optymalny widok, na którym ma się skupić, a następnie stosuje to ustawienie.
Widoki możliwe do zaznaczenia
RotaryService
opiera się na dotychczasowym pomyśle Androida dotyczącym skupienia widoku, który sięga czasów, gdy telefony miały fizyczne klawiatury i joysticki.
Istniejący atrybut android:nextFocusForward
jest używany do elementów obrotowych (patrz Dostosowywanie atrybutu FocusArea), ale atrybuty android:nextFocusLeft
, android:nextFocusRight
, android:nextFocusUp
i android:nextFocusDown
nie są.
RotaryService
skupia się tylko na widokach, które można ustawić jako aktywne. Niektóre widoki,
takie jak Button
s,
zwykle można ustawić jako aktywne. Inne, takie jak TextView
i ViewGroup
, zwykle nie są. Widoki, które można kliknąć, są automatycznie ustawiane na pierwszy plan, a widoki, które można kliknąć, są automatycznie klikalne, gdy mają listenera kliknięcia. Jeśli ta automatyczna logika powoduje pożądaną możliwość skupienia, nie musisz wyraźnie ustawiać możliwości skupienia widoku. Jeśli logika automatyczna nie zapewnia oczekiwanej możliwości skupienia, ustaw atrybut android:focusable
na true
lub false
albo ustaw możliwość skupienia widoku za pomocą atrybutu View.setFocusable(boolean)
. Aby RotaryService
mogło się skupić na tym, widok musi spełniać te wymagania:
- Możliwy do zaznaczenia
- Włączone
- Widoczne
- Szerokość i wysokość muszą mieć wartości niezerowe.
Jeśli widok nie spełnia wszystkich tych wymagań, na przykład przycisk jest aktywny, ale wyłączony, użytkownik nie może użyć pokrętła do jego aktywacji. Jeśli chcesz skupić się na wyłączonych widokach, rozważ użycie stanu niestandardowego zamiast android:state_enabled
, aby kontrolować sposób wyświetlania widoku bez wskazywania, że Android powinien go wyłączyć. Aplikacja może informować użytkownika, dlaczego widok jest wyłączony. W następnej sekcji znajdziesz instrukcje, jak to zrobić.
Stan niestandardowy
Aby dodać stan niestandardowy:
- Aby dodać do widoku atrybut niestandardowy. Aby na przykład dodać stan niestandardowy
state_rotary_enabled
do klasy widokuCustomView
, użyj:<declare-styleable name="CustomView"> <attr name="state_rotary_enabled" format="boolean" /> </declare-styleable>
- Aby śledzić ten stan, dodaj do widoku zmienną instancji wraz z metodami dostępu:
private boolean mRotaryEnabled; public boolean getRotaryEnabled() { return mRotaryEnabled; } public void setRotaryEnabled(boolean rotaryEnabled) { mRotaryEnabled = rotaryEnabled; }
- Aby odczytać wartość atrybutu podczas tworzenia widoku:
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView); mRotaryEnabled = a.getBoolean(R.styleable.CustomView_state_rotary_enabled);
- W klasie widoku zastąpij metodę
onCreateDrawableState()
, a potem w odpowiednich przypadkach dodaj stan niestandardowy. Przykład:@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; }
- Spraw, aby funkcja obsługi kliknięć w widoku działała inaczej w zależności od stanu widoku. Na przykład:
obsługa kliknięcia może nic nie robić lub może wyświetlić komunikat, gdy
mRotaryEnabled
jestfalse
. - Aby przycisk był wyłączony, w elementie rysunkowego tła widoku użyj atrybutu
app:state_rotary_enabled
zamiastandroid:state_enabled
. Jeśli nie masz jeszcze tych informacji, musisz dodać:xmlns:app="http://schemas.android.com/apk/res-auto"
- Jeśli widok jest wyłączony we wszystkich układach, zastąp
android:enabled="false"
wartościąapp:state_rotary_enabled="false"
, a następnie dodaj przestrzeń nazwapp
, jak wyżej. - Jeśli widok jest wyłączony programowo, zastąp wywołania funkcji
setEnabled()
wywołaniami funkcjisetRotaryEnabled()
.
FocusArea
Użyj FocusAreas
, aby podzielić widoki na bloki, aby ułatwić nawigację i ujednolicić aplikację z innymi. Jeśli na przykład aplikacja ma pasek narzędzi, pasek ten powinien znajdować się w oddzielnej FocusArea
od reszty aplikacji. Paski kart i inne elementy nawigacji powinny być również oddzielone od reszty aplikacji. Duże listy powinny mieć zwykle własne FocusArea
. W przeciwnym razie użytkownicy muszą przewijać całą listę, aby uzyskać dostęp do niektórych widoków.
FocusArea
to podklasa LinearLayout
w bibliotece car-ui-library.
Gdy ta funkcja jest włączona, FocusArea
podświetla element, gdy jeden z jego potomków jest zaznaczony. Więcej informacji znajdziesz w artykule Dostosowanie wyróżnienia sekcji fokusa.
Jeśli podczas tworzenia bloku nawigacyjnego w pliku układu chcesz użyć elementu LinearLayout
jako kontenera dla tego bloku, użyj elementu FocusArea
.
W przeciwnym razie owiń blok w FocusArea
.
NIE umieszczaj elementu FocusArea
w innym elemencie FocusArea
.
Spowoduje to niezdefiniowane zachowanie nawigacji. Upewnij się, że wszystkie widoki, które można ustawić w centrum, są umieszczone w elementach FocusArea
.
Poniżej przedstawiamy przykład FocusArea
w ramach 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
działa w ten sposób:
- Podczas obsługi działań obracania i przesuwania
RotaryService
szuka wystąpieńFocusArea
w hierarchii widoku. - Po otrzymaniu zdarzenia rotacji
RotaryService
przenosi fokus na inny widok, który może przejąć fokus w tym samymFocusArea
. - Po otrzymaniu wydarzenia dotyczącego przypomnienia
RotaryService
przenieś fokus na inny widok, który może przejąć fokus w innym (zwykle sąsiednim)FocusArea
.
Jeśli w swoim układzie nie uwzględnisz żadnego elementu FocusAreas
, widok główny zostanie potraktowany jako domyślny obszar fokusu. Użytkownik nie może używać funkcji nudge do nawigacji w aplikacji. Zamiast tego będzie przełączać wszystkie widoki, które można skupić, co może być odpowiednie w przypadku dialogów.
Personalizacja FocusArea
Do dostosowywania nawigacji za pomocą pokrętła można używać 2 standardowych atrybutów widoku:
android:nextFocusForward
pozwala deweloperom aplikacji określić kolejność rotacji w obszarze fokusu. Jest to ten sam atrybut, który służy do kontrolowania kolejności kart w przypadku nawigacji za pomocą klawiatury. NIE używaj tego atrybutu do tworzenia pętli. Zamiast tego użyj funkcjiapp:wrapAround
(patrz poniżej), aby utworzyć pętlę.android:focusedByDefault
pozwala deweloperom aplikacji określić domyślny widok skupienia w oknie. NIE używaj tego atrybutu i atrybutuapp:defaultFocus
(patrz poniżej) w tym samymFocusArea
.
FocusArea
definiuje też niektóre atrybuty, aby umożliwić dostosowywanie nawigacji obrotowej.
Za pomocą tych atrybutów nie można dostosowywać obszarów docelowych z domyślnym punktem skupienia.
- (Android 11 QPR3, Android 11 Car,
Android 12)
app:defaultFocus
można użyć do określenia identyfikatora widoku potomnego, który można ustawić jako aktywny, gdy użytkownik przejdzie do tegoFocusArea
. - (Android 11 QPR3, Android 11 Car,
Android 12)
app:defaultFocusOverridesHistory
może być ustawiony natrue
, aby wybrany widok był aktywny, nawet jeśli historia wskazuje, że inny widok w tymFocusArea
był aktywny. - (Android 12)
Użyj tagówapp:nudgeLeftShortcut
,app:nudgeRightShortcut
,app:nudgeUpShortcut
iapp:nudgeDownShortcut
, aby określić identyfikator widoku potomnego, który można ustawić jako aktywny, gdy użytkownik przesunie palcem w określonym kierunku. Więcej informacji znajdziesz poniżej w sekcji dotyczącej skrótów w powiadomieniach.(Android 11 QPR3, Android 11 Car, wycofane w Androidzie 12)
app:nudgeShortcut
iapp:nudgeShortcutDirection
obsługiwały tylko 1 skrót do funkcji nudge. - (Android 11 QPR3, Android 11 Car,
Android 12)
Aby włączyć zawijanie w tymFocusArea
,app:wrapAround
można ustawić natrue
. Jest to najczęściej używane, gdy widoki są ułożone w kółku lub owalu. - (Android 11 QPR3, Android 11 Car,
Android 12)
Aby dostosować wypełnienie najciekawszych momentów w tymFocusArea
, użyj wartościapp:highlightPaddingStart
,app:highlightPaddingEnd
,app:highlightPaddingTop
,app:highlightPaddingBottom
,app:highlightPaddingHorizontal
, orazapp:highlightPaddingVertical
. - (Android 11 QPR3, Android 11 Car,
Android 12)
Aby dostosować postrzegane granice tegoFocusArea
, aby znaleźć cel pchnięcia, użyjapp:startBoundOffset
,app:endBoundOffset
,app:topBoundOffset
,app:bottomBoundOffset
,app:horizontalBoundOffset
iapp:verticalBoundOffset
. - (Android 11 QPR3, Android 11 Car,
Android 12)
Aby wyraźnie określić identyfikator sąsiedniegoFocusArea
(lub obszarów) w podanych kierunkach, użyj poleceńapp:nudgeLeft
,app:nudgeRight
,app:nudgeUp
iapp:nudgeDown
. Użyj tego, gdy wyszukiwanie geometryczne używane domyślnie nie znajdzie pożądanego celu.
Wskazówki zwykle przenoszą użytkowników między obszarami zainteresowania. Jednak w przypadku skrótów ponaglania ponaglanie czasami najpierw przenosi użytkownika w ramach FocusArea
, więc może być konieczne dwukrotne ponaglanie, aby przejść do następnego FocusArea
. Skróty powiadomień są przydatne, gdy FocusArea
zawiera długą listę, po której następuje przycisk pływający, jak w przykładzie poniżej:

Bez skrótu do funkcji nudge użytkownik musiałby przewinąć całą listę, aby dotrzeć do przycisku FAB.
Dostosowywanie wyróżnienia skupienia
Jak już wspomnieliśmy, RotaryService
opiera się na dotychczasowej koncepcji skupienia widoku w ramach platformy Android. Gdy użytkownik obraca i przesuwa obraz, RotaryService
przenosi punkt skupienia,
przełączając się między widokami. Na Androidzie, gdy widok jest zaznaczony, jeśli widok:
- ma określony własny obszar narożny, Android rysuje obszar narożny widoku;
- Nie określa wyróżnienia punktu skupienia, a domyślne wyróżnienie punktu skupienia nie jest wyłączone. Android wyświetla domyślne wyróżnienie punktu skupienia dla widoku.
Aplikacje zaprojektowane pod kątem korzystania z dotyku zwykle nie określają odpowiednich punktów skupienia.
Domyślne podświetlenie punktu ostrości jest dostarczane przez platformę Android i może być zastąpione przez OEM. Deweloperzy aplikacji otrzymują je, gdy motyw, którego używają, jest pochodną motywu Theme.DeviceDefault
.
Aby zapewnić użytkownikom spójne wrażenia, korzystaj w miarę możliwości z domyślnego wyróżnienia punktu skupienia.
Jeśli potrzebujesz niestandardowego wyróżnienia punktu skupienia (np. okrągłego lub w kształcie pigułki) lub używasz motywu, który nie pochodzi z Theme.DeviceDefault
, użyj zasobów z car-ui-library, aby określić własne wyróżnienie punktu skupienia dla każdego widoku.
Aby określić niestandardowe podświetlenie punktu skupienia w widoku, zmień rysowalną warstwę tła lub pierwszego planu na taką, która różni się od reszty obrazu, gdy widok jest w centrum uwagi. Zwykle zmieniasz tło. Jeśli ten obiekt do rysowania jest używany jako tło w przypadku widoku kwadratowego, powoduje zaokrąglone podświetlenie punktu skupienia:
<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) Pogrubione odwołania do zasobów w powyższym przykładzie wskazują zasoby zdefiniowane przez bibliotekę car-ui-library. Producent OEM zastępuje te wartości, aby były zgodne z domyślnym wyróżnieniem punktu zaznaczenia określonym przez producenta. Dzięki temu kolor podświetlenia punktu skupienia, grubość obrysu itp. nie zmieniają się, gdy użytkownik przechodzi między widokiem z niestandardowym podświetleniem punktu skupienia a widokiem ze standardowym podświetleniem punktu skupienia. Ostatni element to fala używana do dotyku. Wartości domyślne używane w przypadku zasobów pogrubionych:

Dodatkowo niestandardowe podświetlenie obszaru aktywnego jest wywoływane, gdy przycisk ma jednolity kolor tła, aby zwrócić na niego uwagę użytkownika, jak w przykładzie poniżej. Może to utrudniać dostrzeżenie podświetlenia obszaru narożnika. W takim przypadku użyj niestandardowego wyróżnienia za pomocą dodatkowych kolorów:
![]() |
- (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
Przykład:
![]() |
![]() |
|
W trybie ostrości, nie naciśnięte | Ostrość, naciśnięcie |
Przewijanie obrotowe
Jeśli Twoja aplikacja używa RecyclerView
, NALEŻY użyć CarUiRecyclerView
. Dzięki temu interfejs będzie spójny z innymi, ponieważ dostosowywanie OEM dotyczy wszystkich CarUiRecyclerView
.
Jeśli wszystkie elementy na liście można wybrać, nie musisz nic więcej robić. Nawigacja za pomocą przycisku obrotowego przenosi zaznaczenie między elementami na liście, a lista przewija się, aby wyświetlić nowo zaznaczony element.
(Android 11 QPR3, Android 11 Car,
Android 12)
Jeśli w aplikacji występują elementy, na których można i nie można ustawić punktu skupienia, możesz włączyć przewijanie pokrętłem. Dzięki temu użytkownik będzie mógł stopniowo przewijać listę bez pomijania elementów, na których nie można ustawić punktu skupienia. Aby włączyć przewijanie za pomocą pokrętła, ustaw atrybut app:rotaryScrollEnabled
na true
.
(Android 11 QPR3, Android 11 Car,
Android 12)
Możesz włączyć przewijanie za pomocą pokrętła w dowolnym widoku z możliwością przewijania, w tym avCarUiRecyclerView
, za pomocą metody setRotaryScrollEnabled()
w CarUiUtils
. Jeśli to zrobisz, musisz:
- Sprawić, aby można było zaznaczyć widok do przewijania, tak aby można go było zaznaczyć, gdy żaden z widoków potomnych nie jest widoczny;
- Wyłącz domyślne wyróżnienie zaznaczenia w widoku przewijania, wywołując metodę
setDefaultFocusHighlightEnabled(false)
, aby widok przewijania nie był wyróżniony, - Aby upewnić się, że widok przewijany jest skupiony na swoich potomkach, wywołaj funkcję
setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS)
. - Słuchaj zdarzeń MotionEvents z
SOURCE_ROTARY_ENCODER
iAXIS_VSCROLL
lubAXIS_HSCROLL
, aby określić odległość do przewinięcia i kierunek (poprzez znak).
Gdy na CarUiRecyclerView
włączone jest przewijanie za pomocą kółka, a użytkownik przewinie do obszaru, w którym nie ma widoków, które można aktywować, pasek przewijania zmieni kolor z szarego na niebieski, aby wskazać, że jest aktywny. Jeśli chcesz, możesz zastosować podobny efekt.
Zdarzenia MotionEvents są takie same jak te generowane przez kółko myszy, z wyjątkiem źródła.
Tryb bezpośredniej manipulacji
Dotykowe gesty przesuwania i obracania służą zwykle do poruszania się po interfejsie, a kliknięcia przycisku środkowego – do wykonywania czynności, choć nie zawsze tak jest. Jeśli na przykład użytkownik chce dostosować głośność alarmu, może użyć kontrolera obrotowego, aby przejść do suwaka głośności, nacisnąć przycisk Center, obrócić kontroler, aby dostosować głośność alarmu, a następnie nacisnąć przycisk Wstecz, aby powrócić do nawigacji. Jest to tzw. tryb bezpośredniej manipulacji (DM). W tym trybie kontroler obrotowy służy do bezpośredniej interakcji z widokiem, a nie do nawigacji.
Wdrożenie DM na jeden z 2 sposobów. Jeśli musisz tylko obsłużyć obrót, a widok, którym chcesz manipulować, reaguje odpowiednio na ACTION_SCROLL_FORWARD
i ACTION_SCROLL_BACKWARD
AccessibilityEvent
, użyj mechanizmu prostego. W przeciwnym razie użyj mechanizmu zaawansowanego.
Prosty mechanizm jest jedyną opcją w oknach systemowych; aplikacje mogą używać dowolnego mechanizmu.
Prosty mechanizm
(Android 11 QPR3, Android 11 Car,
Android 12)
Aplikacja powinna wywołać funkcję DirectManipulationHelper.setSupportsRotateDirectly(View view, boolean enable)
.
RotaryService
rozpoznaje, kiedy użytkownik jest w trybie DM, i wchodzi w ten tryb, gdy użytkownik naciśnie przycisk środkowy, gdy widok jest aktywny. W trybie DM obracanie wykonuje się za pomocą ACTION_SCROLL_FORWARD
lub ACTION_SCROLL_BACKWARD
, a tryb DM kończy się, gdy użytkownik naciśnie przycisk Wstecz. Prosty mechanizm przełącza wybrany stan widoku podczas wchodzenia do trybu DM i wychodzenia z niego.
Aby wizualnie wskazać, że użytkownik jest w trybie DM, spraw, aby widok wyglądał inaczej po wybraniu. Na przykład zmień tło, gdy android:state_selected
to true
.
Mechanizmy zaawansowane
Aplikacja określa, kiedy RotaryService
wchodzi w tryb DM i z niego wychodzi. Aby zapewnić użytkownikom spójne wrażenia, naciśnięcie przycisku środkowego w przypadku widoku DM powinno aktywować tryb DM, a przycisk Wstecz powinien go wyłączyć. Jeśli nie używasz przycisku środkowego ani funkcji przesuwania, możesz w inny sposób wyjść z trybu DM. W przypadku aplikacji takich jak Mapy można użyć przycisku reprezentującego DM, aby przejść do trybu DM.
Aby obsługiwać zaawansowany tryb DM, widok:
- (Android 11 QPR3, Android 11 Car,
Android 12) MUSI nasłuchiwać zdarzenia
KEYCODE_DPAD_CENTER
w celu przejścia w tryb DM i nasłuchiwać zdarzeniaKEYCODE_BACK
w celu wyjścia z trybu DM, wywołującDirectManipulationHelper.enableDirectManipulationMode()
w każdym przypadku. Aby nasłuchiwać tych zdarzeń, wykonaj jedną z tych czynności:- Zarejestruj
OnKeyListener
.
lub
- Rozszerz widok, a potem zastąpij metodę
dispatchKeyEvent()
.
- Zarejestruj
- NALEŻY nasłuchiwać zdarzeń ponaglania (
KEYCODE_DPAD_UP
,KEYCODE_DPAD_DOWN
,KEYCODE_DPAD_LEFT
lubKEYCODE_DPAD_RIGHT
), jeśli widok ma obsługiwać ponaglania. - Powinien słuchać
MotionEvent
i otrzymywać liczbę rotacji wAXIS_SCROLL
, jeśli widok ma obsługiwać rotację. Możesz to zrobić na kilka sposobów:- Zarejestruj
OnGenericMotionListener
. - Rozszerz widok i zastąpi metodę
dispatchTouchEvent()
.
- Zarejestruj
- Aby uniknąć zablokowania w trybie DM, należy opuścić tryb DM, gdy fragment lub aktywność, do której należy widok, nie jest interaktywny.
- NALEŻY podać wskazówkę wizualną, która wskazuje, że widok jest w trybie DM.
Poniżej przedstawiamy przykład widoku niestandardowego, który wykorzystuje tryb DM do przesuwania i powiększania mapy:
/** 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(); }
Więcej przykładów znajdziesz w projekcie RotaryPlayground
.
ActivityView
Gdy używasz widoku aktywności:
- Element
ActivityView
nie powinien być zaznaczany. - (Android 11 QPR3, Android 11 Car,
wycofane w Androidzie 11)
TreśćActivityView
MUSI zawierać elementFocusParkingView
jako pierwsze widoczne pole, a jego atrybutapp:shouldRestoreFocus
MUSI mieć wartośćfalse
. - Treści w
ActivityView
nie powinny mieć żadnychandroid:focusByDefault
wyświetleń.
Z punktu widzenia użytkownika widoki aktywności nie powinny mieć wpływu na nawigację, z tym wyjątkiem, że obszary fokusu nie mogą obejmować widoków aktywności. Innymi słowy, nie możesz mieć obszaru skupienia, który zawiera treści wewnątrz i na zewnątrz ActivityView
. Jeśli do ActivityView
nie dodasz żadnych obszarów fokusu, element główny hierarchii widoku w ActivityView
zostanie uznany za domyślny obszar fokusu.
przyciski, które działają po przytrzymaniu;
Większość przycisków powoduje jakieś działanie po kliknięciu. Niektóre przyciski działają dopiero po przytrzymaniu.
Na przykład przyciski szybkiego przewijania do przodu i do tyłu zwykle działają, gdy są przytrzymane. Aby takie przyciski obsługiwały przyciski obrotowe, nasłuchuj KEYCODE_DPAD_CENTER
KeyEvents
w taki sposób:
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; });
W którym mRunnable
wykonuje działanie (np. przewijanie) i planuje wykonanie po opóźnieniu.
Tryb dotykowy
Użytkownicy mogą używać kontrolera obrotowego do interakcji z główną jednostką w samochodzie na 2 sposoby: za pomocą kontrolera obrotowego lub dotykając ekranu. Podczas korzystania z kontrolera obrotowego jedno z widoków, które można ustawić jako aktywne, jest wyróżnione. Po dotknięciu ekranu nie pojawia się podświetlenie ostrości. Użytkownik może w dowolnym momencie przełączać się między tymi trybami wprowadzania danych:
- Rotary → touch. Gdy użytkownik dotknie ekranu, podświetlenie zniknie.
- Dotykowy → obrotowy. Gdy użytkownik przesunie, obróci lub naciśnie przycisk Center, pojawi się podświetlenie obszaru nawigacyjnego.
Przyciski Wstecz i Strona główna nie mają wpływu na tryb wprowadzania.
Rotary korzysta z dotychczasowej koncepcji trybu dotykowego w Androidzie.
Możesz użyć parametru View.isInTouchMode()
, aby określić, z jakiego trybu wprowadzania korzysta użytkownik. Możesz użyć funkcji OnTouchModeChangeListener
, aby sprawdzić, czy są jakieś zmiany. Możesz go używać do dostosowywania interfejsu użytkownika do bieżącego trybu wprowadzania, ale unikaj wprowadzania większych zmian, ponieważ mogą one być dezorientujące.
Rozwiązywanie problemów
W aplikacji zaprojektowanej z myślą o używaniu dotykiem często występują zagnieżdżone widoki z możliwością skupienia.
Na przykład wokół elementu ImageButton
może znajdować się element FrameLayout
, na który można najechać kursorem. Nie ma to wpływu na ekran dotykowy, ale może pogorszyć wrażenia użytkownika w przypadku ekranu obrotowego, ponieważ musi on obrócić kontroler 2 razy, aby przejść do następnego widoku interaktywnego. Ze względu na wygodę użytkowników zalecamy, aby można było ustawić fokus na widoku zewnętrznym lub wewnętrznym, ale nie na obu.
Jeśli przycisk lub przełącznik traci fokus po naciśnięciu za pomocą pokrętła, może to być spowodowane jednym z tych czynników:
- Przycisk lub przełącznik jest wyłączany (tymczasowo lub na stałe) z powodu naciśnięcia przycisku. W obu przypadkach możesz rozwiązać ten problem na 2 sposoby:
- Pozostaw stan
android:enabled
jakotrue
i użyj stanu niestandardowego, aby przycisk lub przełącznik był wyszarzony, zgodnie z opisem w sekcji Stan niestandardowy. - Użyj kontenera, aby otoczyć przycisk lub przełącznik, i spraw, aby można było zaznaczyć kontener zamiast przycisku lub przełącznika. (Detektor kliknięcia musi znajdować się w kontenerze).
- Pozostaw stan
- Przycisk lub przełącznik jest wymieniany. Na przykład działanie wykonywane po naciśnięciu przycisku lub przełączeniu przełącznika może powodować odświeżanie dostępnych działań, co powoduje zastępowanie dotychczasowych przycisków nowymi. Możesz to zrobić na 2 sposoby:
- Zamiast tworzyć nowy przycisk lub przełącznik, ustaw ikonę lub tekst istniejącego przycisku lub przełącznika.
- Podobnie jak wyżej, dodaj kontener z możliwością skupienia wokół przycisku lub przełącznika.
RotaryPlayground
RotaryPlayground
to aplikacja referencyjna dla urządzeń rotacyjnych. Dzięki niemu dowiesz się, jak zintegrować funkcje karuzeli w swoich aplikacjach. RotaryPlayground
jest uwzględniany w kompilacji emulatora i kompilacji na urządzenia z systemem operacyjnym Android Automotive (AAOS).
RotaryPlayground
repozytorium:packages/apps/Car/tests/RotaryPlayground/
- Wersje: Android 11 QPR3, Android 11 Car i Android 12
Aplikacja RotaryPlayground
wyświetla po lewej stronie te karty:
- Karty. Testuj nawigację po obszarach fokusu, pomijając elementy, które nie mogą być fokusowane, oraz wprowadzanie tekstu.
- Bezpośrednia manipulacja. Testowanie widżetów, które obsługują prosty i zaawansowany tryb bezpośredniej manipulacji. Ta karta służy do bezpośredniej obsługi w oknie aplikacji.
- Manipulacja interfejsem systemu. Testuj widżety, które obsługują bezpośrednie manipulowanie, w oknach systemowych, w których obsługiwany jest tylko prosty tryb bezpośredniej manipulacji.
- Siatka. Testowanie nawigacji obrotowej w układzie z literą Z z przewijaniem.
- Powiadomienie. Testowanie włączania i wyłączania powiadomień z ostrzeżeniem.
- Przewijanie. Przetestuj przewijanie treści, które można i których nie można zaznaczyć.
- WebView. Testowanie przechodzenia przez linki w
WebView
. - Niestandardowy
FocusArea
Testowanie personalizacjiFocusArea
:- Podsumowanie
android:focusedByDefault
iapp:defaultFocus
.
- Cele dotyczące bezpośrednich podpowiedzi.
- Skróty dotyczące powiadomień.
FocusArea
bez widocznych elementów, które można zaznaczyć.