開發應用程序

以下資料適用於應用程式開發人員。

要使您的應用程式支援旋轉,您必須:

  1. FocusParkingView放置在對應的活動佈局中。
  2. 確保視圖可(或不可)聚焦。
  3. 使用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

要存取模擬旋轉控制器:

  1. 點擊工具列底部的三個點:

    存取模擬旋轉控制器
    圖 1.存取模擬旋轉控制器
  2. 在擴展控制視窗中選擇汽車旋轉

    選擇汽車旋轉
    圖 2.選擇汽車旋轉

USB鍵盤

  • 將 USB 鍵盤插入運行 Android Automotive OS (AAOS) 的設備,在某些情況下,這會阻止螢幕鍵盤出現。
  • 使用userdebugeng版本。
  • 啟用按鍵事件篩選:
    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 。下方顯示的是RotaryPlaygroundFocusParkingView的範例。

<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原因:

  1. 當焦點在另一個視窗中設定時,Android 不會自動清除焦點。如果您嘗試清除前一個視窗中的焦點,Android 會重新對焦該視窗中的視圖,這會導致兩個視窗同時對焦。在每個視窗中新增FocusParkingView可以解決此問題。該視圖是透明的,並且其預設焦點突出顯示已停用,因此無論是否獲得焦點,使用者都看不到它。它可以取得焦點,以便RotaryService可以將焦點停放在其上以刪除焦點突出顯示。
  2. 如果目前視窗中只有一個FocusArea ,則在FocusArea中旋轉控制器會導致RotaryService將焦點從右側視圖移至左側視圖(反之亦然)。將此視圖新增至每個視窗可以解決該問題。當RotaryService確定焦點目標是FocusParkingView時,它可以確定即將發生環繞,此時它透過不移動焦點來避免環繞。
  3. 當旋轉控制啟動應用程式時,Android 會聚焦第一個可聚焦視圖,該視圖始終是FocusParkingViewFocusParkingView決定要聚焦的最佳視圖,然後套用焦點。

可聚焦的視圖

RotaryService建立在 Android 框架現有的視圖焦點概念之上,這個概念可以追溯到手機擁有實體鍵盤和方向鍵的時候。現有的android:nextFocusForward屬性已重新用於旋轉(請參閱FocusArea 自訂),但android:nextFocusLeftandroid:nextFocusRightandroid:nextFocusUpandroid:nextFocusDown則不是。

RotaryService僅關注可聚焦的視圖。某些視圖(例如Button )通常是可聚焦的。其他的,例如TextViewViewGroup ,通常不是。可按一下檢視會自動取得焦點,當檢視具有按一下偵聽器時,檢視會自動可按一下。如果此自動邏輯產生所需的可對焦性,則無需明確設定視圖的可對焦性。如果自動邏輯沒有產生所需的可聚焦性,請將android:focusable屬性設為truefalse ,或使用View.setFocusable(boolean)以程式設計方式設定視圖的可聚焦性。為了讓RotaryService專注於它,視圖必須滿足以下要求:

  • 可對焦
  • 啟用
  • 可見的
  • 寬度和高度具有非零值

如果視圖不符合所有這些要求,例如可聚焦但停用的按鈕,則使用者無法使用旋轉控制將焦點聚焦在該視圖上。如果您希望專注於已停用的視圖,請考慮使用自訂狀態而不是android:state_enabled來控制視圖的顯示方式,而不指示 Android 應將其視為停用。您的應用程式可以告知使用者點擊時視圖被停用的原因。下一節將解釋如何執行此操作。

自訂狀態

新增自訂狀態:

  1. 向您的視圖新增自訂屬性。例如,要將state_rotary_enabled自訂狀態新增至CustomView視圖類,請使用:
    <declare-styleable name="CustomView">
        <attr name="state_rotary_enabled" format="boolean" />
    </declare-styleable>
    
  2. 若要追蹤此狀態,請將實例變數與存取器方法一起新增至視圖:
    private boolean mRotaryEnabled;
    public boolean getRotaryEnabled() { return mRotaryEnabled; }
    public void setRotaryEnabled(boolean rotaryEnabled) {
        mRotaryEnabled = rotaryEnabled;
    }
    
  3. 若要在建立視圖時讀取屬性的值:
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView);
    mRotaryEnabled = a.getBoolean(R.styleable.CustomView_state_rotary_enabled);
    
  4. 在視圖類別中,重寫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;
    }
    
  5. 使視圖的點擊處理程序根據其狀態以不同的方式執行。例如,當mRotaryEnabledfalse時,按一下處理程序可能不執行任何操作,或可能會彈出一個訊息框。
  6. 若要使按鈕顯示為停用,請在檢視的背景可繪製物件中使用app:state_rotary_enabled而不是android:state_enabled 。如果您還沒有,則需要新增:
    xmlns:app="http://schemas.android.com/apk/res-auto"
    
  7. 如果您的檢視在任何佈局中已停用,請將android:enabled="false"替換為app:state_rotary_enabled="false" ,然後新增app命名空間,如上所述。
  8. 如果您的視圖以程式設計方式停用,請將對setEnabled()呼叫替換為對setRotaryEnabled()的呼叫。

重點地區

使用FocusAreas將可聚焦視圖劃分為區塊,以使導航更容易並與其他應用程式保持一致。例如,如果您的應用程式有一個工具列,則該工具列應位於與應用程式其餘部分不同的FocusArea中。選項卡欄和其他導航元素也應與應用程式的其餘部分分開。大型列表通常應該有自己的FocusArea 。如果沒有,使用者必須輪流瀏覽整個清單才能存取某些視圖。

FocusArea是 car-ui-library 中LinearLayout的子類別。啟用此功能後, FocusArea會在其後代之一獲得焦點時繪製突出顯示。要了解更多信息,請參閱焦點突出顯示自訂

在佈局檔案中建立導航區塊時,如果您打算使用LinearLayout作為該區塊的容器,請改用FocusArea 。否則,將該塊包裝在FocusArea中。

不要FocusArea嵌套在另一個FocusArea中。這樣做會導致未定義的導航行為。確保所有可聚焦視圖都嵌套在FocusArea中。

RotaryPlaygroundFocusArea的範例如下所示:

<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工作原理如下:

  1. 當處理旋轉和微移操作時, RotaryService在視圖層次結構中尋找FocusArea的實例。
  2. 當接收到旋轉事件時, RotaryService將焦點移動到另一個可以在同一FocusArea中獲得焦點的 View 。
  3. 當接收到微移事件時, RotaryService將焦點移至另一個視圖,該視圖可以在另一個(通常是相鄰的) FocusArea中取得焦點。

如果佈局中不包含任何FocusAreas ,則根視圖將被視為隱式焦點區域。用戶無法在應用程式中進行導航。相反,它們將在所有可聚焦視圖之間旋轉,這對於對話方塊來說可能足夠了。

焦點區域定制

可以使用兩個標準 View 屬性來自訂旋轉導航:

  • android:nextFocusForward允許應用程式開發人員指定焦點區域中的旋轉順序。此屬性與用於控制鍵盤導航的 Tab 鍵順序的屬性相同。不要使用此屬性來建立循環。相反,使用app:wrapAround (見下文)來創建循環。
  • android:focusedByDefault允許應用程式開發人員指定視窗中的預設焦點視圖。不要在同一個FocusArea中使用此屬性和app:defaultFocus (見下文)。

FocusArea也定義了一些屬性來自訂旋轉導航。無法使用這些屬性自訂隱式焦點區域。

  1. Android 11 QPR3、Android 11 汽車、Android 12
    app:defaultFocus可用於指定可聚焦後代視圖的 ID,當使用者輕移到此FocusArea時,該子視圖應該聚焦。
  2. Android 11 QPR3、Android 11 汽車、Android 12
    app:defaultFocusOverridesHistory可以設定為true以使上面指定的視圖獲得焦點,即使歷史記錄表明此FocusArea中的另一個視圖已獲得焦點。
  3. 安卓12
    使用app:nudgeLeftShortcutapp:nudgeRightShortcutapp:nudgeUpShortcutapp:nudgeDownShortcut指定可聚焦後代視圖的 ID,當使用者向給定方向微移時應聚焦該子視圖。要了解更多信息,請參閱下面的微移快捷方式內容。

    Android 11 QPR3、Android 11 Car,在 Android 12 中已棄用app:nudgeShortcutapp:nudgeShortcutDirection僅支援一種微移快捷方式。

  4. Android 11 QPR3、Android 11 汽車、Android 12
    若要讓旋轉能夠在此FocusArea中環繞,可以將app:wrapAround設為true 。當視圖排列成圓形或橢圓形時,最常使用此方法。
  5. Android 11 QPR3、Android 11 汽車、Android 12
    要調整此FocusArea中突出顯示的填充,請使用app:highlightPaddingStartapp:highlightPaddingEndapp:highlightPaddingTopapp:highlightPaddingBottomapp:highlightPaddingHorizontalapp:highlightPaddingVertical
  6. Android 11 QPR3、Android 11 汽車、Android 12
    要調整此FocusArea的感知邊界以查找微移目標,請使用app:startBoundOffsetapp:endBoundOffsetapp:topBoundOffsetapp:bottomBoundOffsetapp:horizontalBoundOffsetapp:verticalBoundOffset
  7. Android 11 QPR3、Android 11 汽車、Android 12
    若要明確指定給定方向上相鄰FocusArea (或多個區域)的 ID,請使用app:nudgeLeftapp:nudgeRightapp:nudgeUpapp:nudgeDown 。當預設使用的幾何搜尋找不到所需目標時,請使用此選項。

輕推通常在焦點區域之間導航。但使用微移捷徑時,微移有時會先在FocusArea內導航,因此使用者可能需要微移兩次才能導航到下一個FocusArea 。當FocusArea包含一個長列表後面跟著一個Floating Action Button時,微移快捷鍵非常有用,如下例所示:

微移快捷方式
圖 3.微移快捷方式

如果沒有微移快捷方式,使用者將必須旋轉整個清單才能到達 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 會覆寫這些內容,以便與他們指定的預設焦點突出顯示保持一致。這可以確保當使用者在具有自訂焦點突出顯示的視圖和具有預設焦點突出顯示的視圖之間導航時,焦點突出顯示顏色、描邊寬度等不會發生變化。最後一項是用於觸摸的波紋。用於粗體資源的預設值如下所示:

粗體資源的預設值
圖 4.粗體資源的預設值

此外,當為按鈕提供純色背景色以吸引使用者註意時,需要自訂焦點突出顯示,如下例所示。這可能會使焦點高光難以看到。在這種情況下,請使用輔助色指定自訂焦點突出顯示:

純色背景色
  • 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_ENCODERAXIS_VSCROLLAXIS_HSCROLL監聽 MotionEvent,以指示滾動距離和方向(透過標誌)。

當在CarUiRecyclerView上啟用旋轉滾動並且使用者旋轉到不存在可聚焦視圖的區域時,捲軸會從灰色變為藍色,就好像指示捲軸已獲得焦點一樣。如果您願意,您可以實現類似的效果。

除了來源之外,MotionEvent 與滑鼠滾輪產生的 MotionEvent 相同。

直接操控模式

通常情況下,微移和旋轉會在使用者介面中導航,而按下中心按鈕會執行操作,但情況並非總是如此。例如,如果使用者想要調整鬧鐘音量,他們可以使用旋轉控制器導航到音量滑塊,按下中央按鈕,旋轉控制器調整鬧鐘音量,然後按後退按鈕返回導航。這稱為直接操縱(DM)模式。在此模式下,旋轉控制器用於直接與視圖交互,而不是導航。

透過以下兩種方式之一實施 DM。如果您只需要處理旋轉並且要操作的視圖適當地回應ACTION_SCROLL_FORWARDACTION_SCROLL_BACKWARD AccessibilityEvent ,請使用簡單的機制。否則,請使用進階機制。

簡單機制是系統視窗中唯一的選擇;應用程式可以使用任一機制。

機制簡單

Android 11 QPR3、Android 11 汽車、Android 12
您的應用程式應呼叫DirectManipulationHelper.setSupportsRotateDirectly(View view, boolean enable)RotaryService可識別使用者何時處於 DM 模式,並在使用者在視圖對焦時按下中央按鈕時進入 DM 模式。當處於 DM 模式時,旋轉執行ACTION_SCROLL_FORWARDACTION_SCROLL_BACKWARD ,並在使用者按下後退按鈕時退出 DM 模式。當進入和退出 DM 模式時,簡單的機制會切換視圖的選取狀態。

若要提供使用者處於 DM 模式的視覺提示,請使您的視圖在選擇時顯示不同。例如,當android:state_selectedtrue時變更背景。

機制先進

應用程式確定RotaryService何時進入和退出 DM 模式。為了獲得一致的使用者體驗,在 DM 視圖聚焦時按下中央按鈕應進入 DM 模式,而後退按鈕應退出 DM 模式。如果不使用中心按鈕和/或微移,它們可以是退出 DM 模式的替代方法。對於地圖等應用程序,可以使用代表DM的按鈕進入DM模式。

為了支援高階DM模式,視圖:

  1. Android 11 QPR3、Android 11 Car、Android 12 )必須偵聽KEYCODE_DPAD_CENTER事件以進入 DM 模式,並偵聽KEYCODE_BACK事件以退出 DM 模式,在每種情況下呼叫DirectManipulationHelper.enableDirectManipulationMode() 。若要偵聽這些事件,請執行下列操作之一:
    • 註冊一個OnKeyListener
    • 或者,
    • 擴展視圖,然後重寫其dispatchKeyEvent()方法。
  2. 如果視圖應該處理微移,則應該偵聽微移事件( KEYCODE_DPAD_UPKEYCODE_DPAD_DOWNKEYCODE_DPAD_LEFTKEYCODE_DPAD_RIGHT )。
  3. 如果視圖想要處理旋轉,應該監聽MotionEvent並取得AXIS_SCROLL中的旋轉計數。做這件事有很多方法:
    1. 註冊一個OnGenericMotionListener
    2. 擴展視圖並重寫其dispatchTouchEvent()方法。
  4. 為了避免陷入 DM 模式,當視圖所屬的 Fragment 或 Activity 不具有互動性時,必須退出 DM 模式。
  5. 應提供視覺提示來指示視圖處於 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:focusedByDefaultapp:defaultFocus
    • 明確的微調目標。
    • 微移快捷方式。
    • FocusArea沒有可聚焦視圖。