以下資料適用於應用程式開發人員。
要使您的應用程式支援旋轉,您必須:
- 將
FocusParkingView
放置在對應的活動佈局中。 - 確保視圖可(或不可)聚焦。
- 使用
FocusArea
來環繞所有可聚焦視圖(FocusParkingView
除外)。
在設定好開發支援旋轉的應用程式的環境後,下面詳細介紹了其中的每項任務。
設定旋轉控制器
在開始開發支援旋轉的應用程式之前,您需要一個旋轉控制器或替代品。您有如下所述的選項。
模擬器
source build/envsetup.sh && lunch car_x86_64-userdebug m -j emulator -wipe-data -no-snapshot -writable-system
您也可以使用aosp_car_x86_64-userdebug
。
要存取模擬旋轉控制器:
- 點擊工具列底部的三個點:
- 在擴展控制視窗中選擇汽車旋轉:
USB鍵盤
- 將 USB 鍵盤插入運行 Android Automotive OS (AAOS) 的設備,在某些情況下,這會阻止螢幕鍵盤出現。
- 使用
userdebug
或eng
版本。 - 啟用按鍵事件篩選:
adb shell settings put secure android.car.ROTARY_KEY_EVENT_FILTER 1
- 請參考下表尋找每個操作對應的鍵:
鑰匙 旋轉動作 問 逆時針旋轉 乙 順時針旋轉 A 向左微移 D 向右微移 瓦 向上微移 S 向下微移 F 或逗號 中心按鈕 R 或 Esc 返回鍵
亞行命令
您可以使用car_service
指令注入旋轉輸入事件。這些命令可以在運行 Android Automotive OS (AAOS) 的裝置或模擬器上運行。
汽車服務命令 | 旋轉輸入 |
---|---|
adb shell cmd car_service inject-rotary | 逆時針旋轉 |
adb shell cmd car_service inject-rotary -c true | 順時針旋轉 |
adb shell cmd car_service inject-rotary -dt 100 50 | 逆時針旋轉多次(100毫秒前和50毫秒前) |
adb shell cmd car_service inject-key 282 | 向左微移 |
adb shell cmd car_service inject-key 283 | 向右微移 |
adb shell cmd car_service inject-key 280 | 向上微移 |
adb shell cmd car_service inject-key 281 | 向下微移 |
adb shell cmd car_service inject-key 23 | 點擊中心按鈕 |
adb shell input keyevent inject-key 4 | 點選後退按鈕 |
OEM旋轉控制器
當您的旋轉控制器硬體啟動並運行時,這是最現實的選擇。它對於測試快速旋轉特別有用。
焦點停車視圖
FocusParkingView
是汽車 UI 庫 (car-ui-library)中的透明視圖。 RotaryService
使用它來支援旋轉控制器導航。 FocusParkingView
必須是佈局中第一個可聚焦的視圖。它必須放置在所有FocusArea
之外。每個視窗必須有一個FocusParkingView
。如果您已經在使用包含FocusParkingView
car-ui-library 基本佈局,則無需添加另一個FocusParkingView
。下方顯示的是RotaryPlayground
中FocusParkingView
的範例。
<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>
以下是您需要FocusParkingView
原因:
- 當焦點在另一個視窗中設定時,Android 不會自動清除焦點。如果您嘗試清除前一個視窗中的焦點,Android 會重新對焦該視窗中的視圖,這會導致兩個視窗同時對焦。在每個視窗中新增
FocusParkingView
可以解決此問題。該視圖是透明的,並且其預設焦點突出顯示已停用,因此無論是否獲得焦點,使用者都看不到它。它可以取得焦點,以便RotaryService
可以將焦點停放在其上以刪除焦點突出顯示。 - 如果目前視窗中只有一個
FocusArea
,則在FocusArea
中旋轉控制器會導致RotaryService
將焦點從右側視圖移至左側視圖(反之亦然)。將此視圖新增至每個視窗可以解決該問題。當RotaryService
確定焦點目標是FocusParkingView
時,它可以確定即將發生環繞,此時它透過不移動焦點來避免環繞。 - 當旋轉控制啟動應用程式時,Android 會聚焦第一個可聚焦視圖,該視圖始終是
FocusParkingView
。FocusParkingView
決定要聚焦的最佳視圖,然後套用焦點。
可聚焦的視圖
RotaryService
建立在 Android 框架現有的視圖焦點概念之上,這個概念可以追溯到手機擁有實體鍵盤和方向鍵的時候。現有的android:nextFocusForward
屬性已重新用於旋轉(請參閱FocusArea 自訂),但android:nextFocusLeft
、 android:nextFocusRight
、 android:nextFocusUp
和android:nextFocusDown
則不是。
RotaryService
僅關注可聚焦的視圖。某些視圖(例如Button
)通常是可聚焦的。其他的,例如TextView
和ViewGroup
,通常不是。可按一下檢視會自動取得焦點,當檢視具有按一下偵聽器時,檢視會自動可按一下。如果此自動邏輯產生所需的可對焦性,則無需明確設定視圖的可對焦性。如果自動邏輯沒有產生所需的可聚焦性,請將android:focusable
屬性設為true
或false
,或使用View.setFocusable(boolean)
以程式設計方式設定視圖的可聚焦性。為了讓RotaryService
專注於它,視圖必須滿足以下要求:
- 可對焦
- 啟用
- 可見的
- 寬度和高度具有非零值
如果視圖不符合所有這些要求,例如可聚焦但停用的按鈕,則使用者無法使用旋轉控制將焦點聚焦在該視圖上。如果您希望專注於已停用的視圖,請考慮使用自訂狀態而不是android:state_enabled
來控制視圖的顯示方式,而不指示 Android 應將其視為停用。您的應用程式可以告知使用者點擊時視圖被停用的原因。下一節將解釋如何執行此操作。
自訂狀態
新增自訂狀態:
- 向您的視圖新增自訂屬性。例如,要將
state_rotary_enabled
自訂狀態新增至CustomView
視圖類,請使用:<declare-styleable name="CustomView"> <attr name="state_rotary_enabled" format="boolean" /> </declare-styleable>
- 若要追蹤此狀態,請將實例變數與存取器方法一起新增至視圖:
private boolean mRotaryEnabled; public boolean getRotaryEnabled() { return mRotaryEnabled; } public void setRotaryEnabled(boolean rotaryEnabled) { mRotaryEnabled = rotaryEnabled; }
- 若要在建立視圖時讀取屬性的值:
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView); mRotaryEnabled = a.getBoolean(R.styleable.CustomView_state_rotary_enabled);
- 在視圖類別中,重寫
onCreateDrawableState()
方法,然後在適當的時候新增自訂狀態。例如:@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; }
- 使視圖的點擊處理程序根據其狀態以不同的方式執行。例如,當
mRotaryEnabled
為false
時,按一下處理程序可能不執行任何操作,或可能會彈出一個訊息框。 - 若要使按鈕顯示為停用,請在檢視的背景可繪製物件中使用
app:state_rotary_enabled
而不是android:state_enabled
。如果您還沒有,則需要新增:xmlns:app="http://schemas.android.com/apk/res-auto"
- 如果您的檢視在任何佈局中已停用,請將
android:enabled="false"
替換為app:state_rotary_enabled="false"
,然後新增app
命名空間,如上所述。 - 如果您的視圖以程式設計方式停用,請將對
setEnabled()
呼叫替換為對setRotaryEnabled()
的呼叫。
重點地區
使用FocusAreas
將可聚焦視圖劃分為區塊,以使導航更容易並與其他應用程式保持一致。例如,如果您的應用程式有一個工具列,則該工具列應位於與應用程式其餘部分不同的FocusArea
中。選項卡欄和其他導航元素也應與應用程式的其餘部分分開。大型列表通常應該有自己的FocusArea
。如果沒有,使用者必須輪流瀏覽整個清單才能存取某些視圖。
FocusArea
是 car-ui-library 中LinearLayout
的子類別。啟用此功能後, FocusArea
會在其後代之一獲得焦點時繪製突出顯示。要了解更多信息,請參閱焦點突出顯示自訂。
在佈局檔案中建立導航區塊時,如果您打算使用LinearLayout
作為該區塊的容器,請改用FocusArea
。否則,將該塊包裝在FocusArea
中。
不要將FocusArea
嵌套在另一個FocusArea
中。這樣做會導致未定義的導航行為。確保所有可聚焦視圖都嵌套在FocusArea
中。
RotaryPlayground
中FocusArea
的範例如下所示:
<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
工作原理如下:
- 當處理旋轉和微移操作時,
RotaryService
在視圖層次結構中尋找FocusArea
的實例。 - 當接收到旋轉事件時,
RotaryService
將焦點移動到另一個可以在同一FocusArea
中獲得焦點的 View 。 - 當接收到微移事件時,
RotaryService
將焦點移至另一個視圖,該視圖可以在另一個(通常是相鄰的)FocusArea
中取得焦點。
如果佈局中不包含任何FocusAreas
,則根視圖將被視為隱式焦點區域。用戶無法在應用程式中進行導航。相反,它們將在所有可聚焦視圖之間旋轉,這對於對話方塊來說可能足夠了。
焦點區域定制
可以使用兩個標準 View 屬性來自訂旋轉導航:
-
android:nextFocusForward
允許應用程式開發人員指定焦點區域中的旋轉順序。此屬性與用於控制鍵盤導航的 Tab 鍵順序的屬性相同。不要使用此屬性來建立循環。相反,使用app:wrapAround
(見下文)來創建循環。 -
android:focusedByDefault
允許應用程式開發人員指定視窗中的預設焦點視圖。不要在同一個FocusArea
中使用此屬性和app:defaultFocus
(見下文)。
FocusArea
也定義了一些屬性來自訂旋轉導航。無法使用這些屬性自訂隱式焦點區域。
- ( Android 11 QPR3、Android 11 汽車、Android 12 )
app:defaultFocus
可用於指定可聚焦後代視圖的 ID,當使用者輕移到此FocusArea
時,該子視圖應該聚焦。 - ( Android 11 QPR3、Android 11 汽車、Android 12 )
app:defaultFocusOverridesHistory
可以設定為true
以使上面指定的視圖獲得焦點,即使歷史記錄表明此FocusArea
中的另一個視圖已獲得焦點。 - (安卓12 )
使用app:nudgeLeftShortcut
、app:nudgeRightShortcut
、app:nudgeUpShortcut
和app:nudgeDownShortcut
指定可聚焦後代視圖的 ID,當使用者向給定方向微移時應聚焦該子視圖。要了解更多信息,請參閱下面的微移快捷方式內容。( Android 11 QPR3、Android 11 Car,在 Android 12 中已棄用)
app:nudgeShortcut
和app:nudgeShortcutDirection
僅支援一種微移快捷方式。 - ( Android 11 QPR3、Android 11 汽車、Android 12 )
若要讓旋轉能夠在此FocusArea
中環繞,可以將app:wrapAround
設為true
。當視圖排列成圓形或橢圓形時,最常使用此方法。 - ( Android 11 QPR3、Android 11 汽車、Android 12 )
要調整此FocusArea
中突出顯示的填充,請使用app:highlightPaddingStart
、app:highlightPaddingEnd
、app:highlightPaddingTop
、app:highlightPaddingBottom
、app:highlightPaddingHorizontal
和app:highlightPaddingVertical
。 - ( Android 11 QPR3、Android 11 汽車、Android 12 )
要調整此FocusArea
的感知邊界以查找微移目標,請使用app:startBoundOffset
、app:endBoundOffset
、app:topBoundOffset
、app:bottomBoundOffset
、app:horizontalBoundOffset
和app:verticalBoundOffset
。 - ( Android 11 QPR3、Android 11 汽車、Android 12 )
若要明確指定給定方向上相鄰FocusArea
(或多個區域)的 ID,請使用app:nudgeLeft
、app:nudgeRight
、app:nudgeUp
和app:nudgeDown
。當預設使用的幾何搜尋找不到所需目標時,請使用此選項。
輕推通常在焦點區域之間導航。但使用微移捷徑時,微移有時會先在FocusArea
內導航,因此使用者可能需要微移兩次才能導航到下一個FocusArea
。當FocusArea
包含一個長列表後面跟著一個Floating Action Button時,微移快捷鍵非常有用,如下例所示:
如果沒有微移快捷方式,使用者將必須旋轉整個清單才能到達 FAB。
焦點高亮定制
如上所述, RotaryService
建構在 Android 框架現有的視圖焦點概念之上。當使用者旋轉和輕移時, RotaryService
會移動焦點,聚焦一個視圖並取消聚焦另一個視圖。在 Android 中,當視圖獲得焦點時,如果視圖:
- 指定了自己的焦點高亮,Android 繪製視圖的焦點高亮。
- 不指定焦點突出顯示,且預設焦點突出顯示未停用,Android 會為視圖繪製預設焦點突出顯示。
專為觸控設計的應用程式通常不會指定適當的焦點突出顯示。
預設焦點突出顯示由 Android 框架提供,可由 OEM 覆蓋。當應用程式開發人員使用的主題派生自Theme.DeviceDefault
時,他們會收到它。
為了獲得一致的使用者體驗,請盡可能依賴預設的焦點突出顯示。如果您需要自訂形狀(例如圓形或藥丸形)焦點突出顯示,或者如果您使用的主題不是從Theme.DeviceDefault
派生的,請使用 car-ui-library 資源指定您自己的焦點突出顯示每個視圖。
若要為視圖指定自訂焦點反白顯示,請將視圖的背景或前景可繪製物件變更為視圖對焦時不同的可繪製物件。通常,您會更改背景。以下可繪製物件如果用作方形視圖的背景,則會產生圓形焦點突出顯示:
<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 )上述範例中的粗體資源參考標識由 car-ui-library 定義的資源。 OEM 會覆寫這些內容,以便與他們指定的預設焦點突出顯示保持一致。這可以確保當使用者在具有自訂焦點突出顯示的視圖和具有預設焦點突出顯示的視圖之間導航時,焦點突出顯示顏色、描邊寬度等不會發生變化。最後一項是用於觸摸的波紋。用於粗體資源的預設值如下所示:
此外,當為按鈕提供純色背景色以吸引使用者註意時,需要自訂焦點突出顯示,如下例所示。這可能會使焦點高光難以看到。在這種情況下,請使用輔助色指定自訂焦點突出顯示:
- ( Android 11 QPR3、Android 11 汽車、Android 12 )
car_ui_rotary_focus_fill_secondary_color
car_ui_rotary_focus_stroke_secondary_color
- (安卓12 )
car_ui_rotary_focus_pressed_fill_secondary_color
car_ui_rotary_focus_pressed_stroke_secondary_color
例如:
專注,不壓抑 | 專注、按下 |
旋轉滾動
如果您的應用程式使用RecyclerView
,您應該使用CarUiRecyclerView
。這可確保您的 UI 與其他 UI 保持一致,因為 OEM 的自訂適用於所有CarUiRecyclerView
。
如果清單中的元素都是可聚焦的,則無需執行任何其他操作。旋轉導航將焦點移動到清單中的元素,並且清單會滾動以使新聚焦的元素可見。
( Android 11 QPR3、Android 11 汽車、Android 12 )
如果混合存在可聚焦和不可聚焦的元素,或者所有元素都不可聚焦,則可以啟用旋轉滾動,這允許使用者使用旋轉控制器逐漸滾動列表,而不會跳過不可聚焦的項目。若要啟用旋轉捲動,請將app:rotaryScrollEnabled
屬性設為true
。
( Android 11 QPR3、Android 11 汽車、Android 12 )
您可以使用CarUiUtils
中的setRotaryScrollEnabled()
方法在任何可滾動視圖(包括 av CarUiRecyclerView
中啟用旋轉滾動。如果您這樣做,您需要:
- 使可捲動視圖可聚焦,以便在其可聚焦後代視圖都不可見時可以聚焦到它,
- 透過呼叫
setDefaultFocusHighlightEnabled(false)
來停用可捲動視圖上的預設焦點反白顯示,以便可捲動視圖看起來不會獲得焦點, - 透過呼叫
setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS)
確保可捲動視圖在其後代之前獲得焦點。 - 使用
SOURCE_ROTARY_ENCODER
和AXIS_VSCROLL
或AXIS_HSCROLL
監聽 MotionEvent,以指示滾動距離和方向(透過標誌)。
當在CarUiRecyclerView
上啟用旋轉滾動並且使用者旋轉到不存在可聚焦視圖的區域時,捲軸會從灰色變為藍色,就好像指示捲軸已獲得焦點一樣。如果您願意,您可以實現類似的效果。
除了來源之外,MotionEvent 與滑鼠滾輪產生的 MotionEvent 相同。
直接操控模式
通常情況下,微移和旋轉會在使用者介面中導航,而按下中心按鈕會執行操作,但情況並非總是如此。例如,如果使用者想要調整鬧鐘音量,他們可以使用旋轉控制器導航到音量滑塊,按下中央按鈕,旋轉控制器調整鬧鐘音量,然後按後退按鈕返回導航。這稱為直接操縱(DM)模式。在此模式下,旋轉控制器用於直接與視圖交互,而不是導航。
透過以下兩種方式之一實施 DM。如果您只需要處理旋轉並且要操作的視圖適當地回應ACTION_SCROLL_FORWARD
和ACTION_SCROLL_BACKWARD
AccessibilityEvent
,請使用簡單的機制。否則,請使用進階機制。
簡單機制是系統視窗中唯一的選擇;應用程式可以使用任一機制。
機制簡單
( Android 11 QPR3、Android 11 汽車、Android 12 )
您的應用程式應呼叫DirectManipulationHelper.setSupportsRotateDirectly(View view, boolean enable)
。 RotaryService
可識別使用者何時處於 DM 模式,並在使用者在視圖對焦時按下中央按鈕時進入 DM 模式。當處於 DM 模式時,旋轉執行ACTION_SCROLL_FORWARD
或ACTION_SCROLL_BACKWARD
,並在使用者按下後退按鈕時退出 DM 模式。當進入和退出 DM 模式時,簡單的機制會切換視圖的選取狀態。
若要提供使用者處於 DM 模式的視覺提示,請使您的視圖在選擇時顯示不同。例如,當android:state_selected
為true
時變更背景。
機制先進
應用程式確定RotaryService
何時進入和退出 DM 模式。為了獲得一致的使用者體驗,在 DM 視圖聚焦時按下中央按鈕應進入 DM 模式,而後退按鈕應退出 DM 模式。如果不使用中心按鈕和/或微移,它們可以是退出 DM 模式的替代方法。對於地圖等應用程序,可以使用代表DM的按鈕進入DM模式。
為了支援高階DM模式,視圖:
- ( Android 11 QPR3、Android 11 Car、Android 12 )必須偵聽
KEYCODE_DPAD_CENTER
事件以進入 DM 模式,並偵聽KEYCODE_BACK
事件以退出 DM 模式,在每種情況下呼叫DirectManipulationHelper.enableDirectManipulationMode()
。若要偵聽這些事件,請執行下列操作之一:- 註冊一個
OnKeyListener
。 或者, - 擴展視圖,然後重寫其
dispatchKeyEvent()
方法。
- 註冊一個
- 如果視圖應該處理微移,則應該偵聽微移事件(
KEYCODE_DPAD_UP
、KEYCODE_DPAD_DOWN
、KEYCODE_DPAD_LEFT
或KEYCODE_DPAD_RIGHT
)。 - 如果視圖想要處理旋轉,應該監聽
MotionEvent
並取得AXIS_SCROLL
中的旋轉計數。做這件事有很多方法:- 註冊一個
OnGenericMotionListener
。 - 擴展視圖並重寫其
dispatchTouchEvent()
方法。
- 註冊一個
- 為了避免陷入 DM 模式,當視圖所屬的 Fragment 或 Activity 不具有互動性時,必須退出 DM 模式。
- 應提供視覺提示來指示視圖處於 DM 模式。
下面提供了使用 DM 模式平移和縮放地圖的自訂視圖範例:
/** 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(); }
更多範例可以在RotaryPlayground
專案中找到。
活動視圖
使用 ActivityView 時:
-
ActivityView
不應該是可聚焦的。 - ( Android 11 QPR3、Android 11 汽車、Android 11 中已棄用)
ActivityView
的內容必須包含FocusParkingView
作為第一個可聚焦視圖,且其app:shouldRestoreFocus
屬性必須為false
。 -
ActivityView
的內容不應有android:focusByDefault
視圖。
對於使用者來說,除了焦點區域不能跨越 ActivityView 之外,ActivityView 不應該對導航產生任何影響。換句話說,您不能擁有一個在ActivityView
內部和外部都包含內容的焦點區域。如果您沒有在ActivityView
新增任何 FocusAreas,則ActivityView
中視圖層次結構的根將被視為隱式焦點區域。
按住時可操作的按鈕
大多數按鈕在單擊時都會引起一些操作。有些按鈕在按住時才起作用。例如,快轉和快退按鈕通常在按住時運行。若要讓此類按鈕支援旋轉,請偵聽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; });
其中mRunnable
執行一個操作(例如倒帶)並安排自己在延遲後運行。
觸控模式
使用者可以透過兩種方式使用旋轉控制器與汽車主機互動:使用旋轉控制器或觸控螢幕。使用旋轉控制器時,可聚焦視圖之一會反白顯示。觸控螢幕時,不會出現焦點反白。使用者可以隨時在這些輸入模式之間切換:
- 旋轉→觸摸。當使用者觸摸螢幕時,焦點突出顯示就會消失。
- 觸摸 → 旋轉。當使用者輕推、旋轉或按下中央按鈕時,會出現焦點突出顯示。
返回和主頁按鈕對輸入模式沒有影響。
旋轉搭載了 Android 現有的觸控模式概念。您可以使用View.isInTouchMode()
來確定使用者正在使用哪種輸入模式。您可以使用OnTouchModeChangeListener
來監聽更改。雖然這可用於針對當前輸入模式自訂使用者介面,但請避免任何重大更改,因為它們可能會令人不安。
故障排除
在專為觸控設計的應用程式中,通常具有嵌套的可聚焦視圖。例如, ImageButton
周圍可能有一個FrameLayout
,兩者都是可聚焦的。這對觸控沒有任何損害,但可能會導致旋轉的使用者體驗不佳,因為使用者必須旋轉控制器兩次才能移動到下一個互動式視圖。為了獲得良好的使用者體驗,Google 建議您將外部視圖或內部視圖設定為可聚焦的,但不要同時設定兩者。
如果透過旋轉控制器按下按鈕或開關時失去焦點,則可能存在以下情況之一:
- 由於按下按鈕,按鈕或開關被停用(短暫或無限期)。無論哪種情況,都有兩種方法可以解決此問題:
- 將
android:enabled
狀態保留為true
並使用自訂狀態使按鈕或開關變灰,如自訂狀態所述。 - 使用容器包圍按鈕或開關,並使容器(而不是按鈕或開關)可對焦。 (點擊偵聽器必須位於容器上。)
- 將
- 正在更換按鈕或開關。例如,按下按鈕或切換開關時採取的操作可能會觸發可用操作的刷新,從而導致新按鈕取代現有按鈕。有兩種方法可以解決這個問題:
- 設定現有按鈕或開關的圖示和/或文本,而不是建立新按鈕或開關。
- 如上所述,在按鈕或開關周圍添加一個可聚焦的容器。
扶輪遊樂場
RotaryPlayground
是旋轉的參考應用程式。使用它來了解如何將旋轉功能整合到您的應用程式中。 RotaryPlayground
包含在模擬器建置以及運行 Android Automotive OS (AAOS) 的裝置建置中。
-
RotaryPlayground
儲存庫:packages/apps/Car/tests/RotaryPlayground/
- 版本:Android 11 QPR3、Android 11 汽車和 Android 12
RotaryPlayground
應用程式在左側顯示以下選項卡:
- 牌。測試圍繞焦點區域導航,跳過不可聚焦的元素和文字輸入。
- 直接操縱。測試支援簡單和進階直接操作模式的小部件。此選項卡專門用於在應用程式視窗內直接操作。
- 系統 UI 操作。測試支援在僅支援簡單直接操作模式的系統視窗中直接操作的小部件。
- 網格。透過滾動測試 z 模式旋轉導航。
- 通知。測試推播通知的進出。
- 滾動。測試滾動可聚焦和不可聚焦內容的組合。
- 網頁視圖。測試透過
WebView
中的連結進行導航。 - 自訂
FocusArea
。測試FocusArea
定制:- 環繞式。
-
android:focusedByDefault
和app:defaultFocus
。 - 明確的微調目標。
- 微移快捷方式。
-
FocusArea
沒有可聚焦視圖。