Phát triển ứng dụng

Tài liệu sau đây dành cho các nhà phát triển ứng dụng.

Để làm cho ứng dụng của bạn quay vòng, bạn PHẢI:

  1. Đặt FocusParkingView trong bố cục hoạt động tương ứng.
  2. Đảm bảo các chế độ xem có thể (hoặc không) có thể lấy tiêu điểm.
  3. Sử dụng FocusArea để bao quanh tất cả các chế độ xem có thể lấy tiêu điểm của bạn, ngoại trừ FocusParkingView .

Mỗi tác vụ này được trình bày chi tiết bên dưới, sau khi bạn thiết lập môi trường của mình để phát triển các ứng dụng hỗ trợ quay.

Thiết lập bộ điều khiển quay

Trước khi có thể bắt đầu phát triển các ứng dụng hỗ trợ quay, bạn cần có bộ điều khiển quay hoặc thiết bị thay thế. Bạn có các tùy chọn được mô tả bên dưới.

Giả lập

source build/envsetup.sh && lunch car_x86_64-userdebug
m -j
emulator -wipe-data -no-snapshot -writable-system

Bạn cũng có thể sử dụng aosp_car_x86_64-userdebug .

Để truy cập bộ điều khiển quay mô phỏng:

  1. Nhấn vào ba dấu chấm ở cuối thanh công cụ:

    Truy cập bộ điều khiển quay mô phỏng
    Hình 1. Bộ điều khiển quay mô phỏng Access
  2. Chọn Vòng quay ô tô trong cửa sổ điều khiển mở rộng:

    Chọn Vòng quay ô tô
    Hình 2. Chọn Vòng quay ô tô

bàn phím USB

  • Cắm bàn phím USB vào thiết bị chạy Android Automotive OS (AAOS). Trong một số trường hợp, điều này ngăn bàn phím ảo xuất hiện.
  • Sử dụng userdebug hoặc eng build.
  • Bật tính năng lọc sự kiện quan trọng:
    adb shell settings put secure android.car.ROTARY_KEY_EVENT_FILTER 1
    
  • Xem bảng bên dưới để tìm key tương ứng cho từng hành động:
    Chìa khóa Hành động quay
    Q Xoay ngược chiều kim đồng hồ
    E Xoay theo chiều kim đồng hồ
    MỘT Di chuyển sang trái
    D Di chuyển sang phải
    W Đẩy lên
    S Đẩy xuống
    F hoặc dấu phẩy Nút giữa
    R hoặc Esc Nút quay lại

lệnh ADB

Bạn có thể sử dụng lệnh car_service để đưa vào các sự kiện đầu vào quay. Các lệnh này có thể chạy trên các thiết bị chạy Android Automotive OS (AAOS) hoặc trên trình mô phỏng.

lệnh car_service Đầu vào quay
adb shell cmd car_service inject-rotary Xoay ngược chiều kim đồng hồ
adb shell cmd car_service inject-rotary -c true Xoay theo chiều kim đồng hồ
adb shell cmd car_service inject-rotary -dt 100 50 Xoay ngược chiều kim đồng hồ nhiều lần (cách đây 100 mili giây và cách đây 50 mili giây)
adb shell cmd car_service inject-key 282 Di chuyển sang trái
adb shell cmd car_service inject-key 283 Di chuyển sang phải
adb shell cmd car_service inject-key 280 Đẩy lên
adb shell cmd car_service inject-key 281 Đẩy xuống
adb shell cmd car_service inject-key 23 Bấm nút giữa
adb shell input keyevent inject-key 4 Bấm nút quay lại

Bộ điều khiển quay OEM

Khi phần cứng bộ điều khiển quay của bạn hoạt động, đây là tùy chọn thực tế nhất. Nó đặc biệt hữu ích để thử nghiệm khả năng quay nhanh.

Tập TrungBãi Đậu XeXem

FocusParkingView là chế độ xem trong suốt trong Thư viện UI ô tô (car-ui-library) . RotaryService sử dụng nó để hỗ trợ điều hướng bộ điều khiển quay. FocusParkingView phải là chế độ xem có thể lấy tiêu điểm đầu tiên trong bố cục. Nó phải được đặt bên ngoài tất cả FocusArea s. Mỗi cửa sổ phải có một FocusParkingView . Nếu bạn đang sử dụng bố cục cơ sở thư viện ô tô-ui-library có chứa FocusParkingView thì bạn không cần thêm FocusParkingView khác. Dưới đây là ví dụ về FocusParkingView trong 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>

Dưới đây là những lý do bạn cần FocusParkingView :

  1. Android không tự động xóa tiêu điểm khi tiêu điểm được đặt trong một cửa sổ khác. Nếu bạn cố gắng xóa tiêu điểm trong cửa sổ trước, Android sẽ lấy nét lại chế độ xem trong cửa sổ đó, dẫn đến hai cửa sổ được lấy tiêu điểm cùng lúc. Việc thêm FocusParkingView vào mỗi cửa sổ có thể khắc phục sự cố này. Chế độ xem này trong suốt và phần đánh dấu tiêu điểm mặc định của nó bị tắt, do đó nó không hiển thị với người dùng cho dù có được lấy nét hay không. Nó có thể lấy tiêu điểm để RotaryService có thể đặt tiêu điểm vào đó để loại bỏ phần đánh dấu tiêu điểm.
  2. Nếu chỉ có một FocusArea trong cửa sổ hiện tại, việc xoay bộ điều khiển trong FocusArea sẽ khiến RotaryService di chuyển tiêu điểm từ chế độ xem bên phải sang chế độ xem bên trái (và ngược lại). Việc thêm chế độ xem này vào mỗi cửa sổ có thể khắc phục được sự cố. Khi RotaryService xác định mục tiêu tiêu điểm là FocusParkingView , nó có thể xác định việc bao bọc sắp xảy ra tại thời điểm đó nó tránh được việc bao quanh bằng cách không di chuyển tiêu điểm.
  3. Khi điều khiển xoay khởi chạy một ứng dụng, Android sẽ tập trung vào chế độ xem có thể lấy tiêu điểm đầu tiên, luôn là FocusParkingView . FocusParkingView xác định chế độ xem tối ưu để lấy nét và sau đó áp dụng tiêu điểm.

Chế độ xem có thể tập trung

RotaryService được xây dựng dựa trên khái niệm tập trung vào chế độ xem hiện có của khung Android, có từ thời điện thoại có bàn phím vật lý và D-pad. Thuộc tính android:nextFocusForward hiện tại được tái sử dụng cho tính năng quay (xem tùy chỉnh FocusArea ), nhưng android:nextFocusLeft , android:nextFocusRight , android:nextFocusUpandroid:nextFocusDown thì không.

RotaryService chỉ tập trung vào các chế độ xem có thể lấy tiêu điểm. Một số chế độ xem, chẳng hạn như Button s, thường có thể lấy tiêu điểm. Những cái khác, chẳng hạn như TextView s và ViewGroup s, thường không có. Các chế độ xem có thể nhấp sẽ tự động có thể lấy tiêu điểm và các chế độ xem sẽ tự động có thể nhấp khi chúng có trình xử lý lượt nhấp. Nếu logic tự động này mang lại khả năng lấy nét mong muốn thì bạn không cần đặt rõ ràng khả năng lấy nét của chế độ xem. Nếu logic tự động không mang lại khả năng lấy nét như mong muốn, hãy đặt thuộc android:focusable thành true hoặc false hoặc đặt khả năng lấy nét của chế độ xem theo chương trình với View.setFocusable(boolean) . Để RotaryService tập trung vào nó, chế độ xem PHẢI đáp ứng các yêu cầu sau:

  • Có thể lấy nét
  • Đã bật
  • Dễ thấy
  • Có giá trị khác 0 cho chiều rộng và chiều cao

Nếu chế độ xem không đáp ứng tất cả các yêu cầu này, chẳng hạn như nút có thể lấy tiêu điểm nhưng bị vô hiệu hóa, thì người dùng không thể sử dụng điều khiển xoay để lấy tiêu điểm vào chế độ xem đó. Nếu bạn muốn tập trung vào chế độ xem bị vô hiệu hóa, hãy cân nhắc sử dụng trạng thái tùy chỉnh thay vì android:state_enabled để kiểm soát cách chế độ xem xuất hiện mà không cho biết rằng Android nên coi chế độ xem đó bị vô hiệu hóa. Ứng dụng của bạn có thể thông báo cho người dùng lý do chế độ xem bị tắt khi nhấn vào. Phần tiếp theo giải thích cách thực hiện việc này.

Trạng thái tùy chỉnh

Để thêm trạng thái tùy chỉnh:

  1. Để thêm thuộc tính tùy chỉnh vào chế độ xem của bạn. Ví dụ: để thêm trạng thái tùy chỉnh state_rotary_enabled vào lớp chế độ xem CustomView , hãy sử dụng:
    <declare-styleable name="CustomView">
        <attr name="state_rotary_enabled" format="boolean" />
    </declare-styleable>
    
  2. Để theo dõi trạng thái này, hãy thêm một biến thể hiện vào chế độ xem của bạn cùng với các phương thức truy cập:
    private boolean mRotaryEnabled;
    public boolean getRotaryEnabled() { return mRotaryEnabled; }
    public void setRotaryEnabled(boolean rotaryEnabled) {
        mRotaryEnabled = rotaryEnabled;
    }
    
  3. Để đọc giá trị thuộc tính của bạn khi chế độ xem của bạn được tạo:
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView);
    mRotaryEnabled = a.getBoolean(R.styleable.CustomView_state_rotary_enabled);
    
  4. Trong lớp dạng xem của bạn, hãy ghi đè phương thức onCreateDrawableState() rồi thêm trạng thái tùy chỉnh khi thích hợp. Ví dụ:
    @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. Làm cho trình xử lý nhấp chuột của chế độ xem của bạn hoạt động khác nhau tùy thuộc vào trạng thái của nó. Ví dụ: trình xử lý nhấp chuột có thể không làm gì hoặc nó có thể bật lên một lời chúc mừng khi mRotaryEnabled false .
  6. Để làm cho nút có vẻ bị tắt, trong nền có thể vẽ được của chế độ xem của bạn, hãy sử dụng app:state_rotary_enabled thay vì android:state_enabled . Nếu chưa có thì bạn cần thêm:
    xmlns:app="http://schemas.android.com/apk/res-auto"
    
  7. Nếu chế độ xem của bạn bị tắt trong bất kỳ bố cục nào, hãy thay thế android:enabled="false" bằng app:state_rotary_enabled="false" rồi thêm vùng tên app , như trên.
  8. Nếu chế độ xem của bạn bị tắt theo chương trình, hãy thay thế lệnh gọi setEnabled() bằng lệnh gọi setRotaryEnabled() .

Khu vực tập trung

Sử dụng FocusAreas để phân vùng các chế độ xem có thể lấy tiêu điểm thành các khối nhằm giúp điều hướng dễ dàng hơn và nhất quán với các ứng dụng khác. Ví dụ: nếu ứng dụng của bạn có thanh công cụ thì thanh công cụ đó phải nằm trong một FocusArea riêng biệt với phần còn lại của ứng dụng. Thanh tab và các thành phần điều hướng khác cũng phải được tách biệt khỏi phần còn lại của ứng dụng. Các danh sách lớn thường phải có FocusArea riêng. Nếu không, người dùng phải xoay qua toàn bộ danh sách để truy cập một số chế độ xem.

FocusArea là một lớp con của LinearLayout trong thư viện car-ui. Khi tính năng này được bật, FocusArea sẽ nổi bật khi một trong các thành phần con của nó được lấy nét. Để tìm hiểu thêm, hãy xem Tùy chỉnh tiêu điểm nổi bật .

Khi tạo khối điều hướng trong tệp bố cục, nếu bạn định sử dụng LinearLayout làm vùng chứa cho khối đó, hãy sử dụng FocusArea thay thế. Nếu không, hãy bọc khối trong FocusArea .

KHÔNG lồng FocusArea vào FocusArea khác. Làm như vậy sẽ dẫn đến hành vi điều hướng không xác định. Đảm bảo rằng tất cả các chế độ xem có thể lấy tiêu điểm đều được lồng trong FocusArea .

Một ví dụ về FocusArea trong RotaryPlayground được hiển thị bên dưới:

<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 hoạt động như sau:

  1. Khi xử lý các hành động xoay và di chuyển, RotaryService sẽ tìm kiếm các phiên bản của FocusArea trong hệ thống phân cấp chế độ xem.
  2. Khi nhận được sự kiện xoay vòng, RotaryService sẽ chuyển tiêu điểm sang một Chế độ xem khác có thể lấy tiêu điểm trong cùng FocusArea .
  3. Khi nhận được một sự kiện nâng cao, RotaryService sẽ di chuyển tiêu điểm sang một chế độ xem khác có thể lấy tiêu điểm ở một FocusArea khác (thường liền kề).

Nếu bạn không bao gồm bất kỳ FocusAreas trong bố cục của mình thì chế độ xem gốc sẽ được coi là vùng lấy nét ngầm. Người dùng không thể di chuyển để điều hướng trong ứng dụng. Thay vào đó, chúng sẽ xoay qua tất cả các chế độ xem có thể lấy tiêu điểm, điều này có thể phù hợp với các hộp thoại.

Tùy chỉnh vùng lấy nét

Hai thuộc tính Chế độ xem tiêu chuẩn có thể được sử dụng để tùy chỉnh điều hướng quay:

  • android:nextFocusForward cho phép nhà phát triển ứng dụng chỉ định thứ tự xoay trong vùng trọng tâm. Đây là thuộc tính tương tự được sử dụng để kiểm soát thứ tự Tab cho điều hướng bàn phím. KHÔNG sử dụng thuộc tính này để tạo vòng lặp. Thay vào đó, hãy sử dụng app:wrapAround (xem bên dưới) để tạo vòng lặp.
  • android:focusedByDefault cho phép nhà phát triển ứng dụng chỉ định chế độ xem tiêu điểm mặc định trong cửa sổ. KHÔNG sử dụng thuộc tính này và app:defaultFocus (xem bên dưới) trong cùng một FocusArea .

FocusArea cũng xác định một số thuộc tính để tùy chỉnh điều hướng quay. Không thể tùy chỉnh các vùng tiêu điểm ngầm định bằng các thuộc tính này.

  1. ( Android 11 QPR3, Android 11 Ô tô, Android 12 )
    app:defaultFocus có thể được sử dụng để chỉ định ID của chế độ xem con có thể lấy tiêu điểm, chế độ xem này sẽ được tập trung vào khi người dùng di chuyển tới FocusArea này.
  2. ( Android 11 QPR3, Android 11 Ô tô, Android 12 )
    app:defaultFocusOverridesHistory có thể được đặt thành true để làm cho chế độ xem được chỉ định ở trên lấy tiêu điểm ngay cả khi có lịch sử để biểu thị một chế độ xem khác trong FocusArea này đã được tập trung vào.
  3. ( Android 12 )
    Sử dụng app:nudgeLeftShortcut , app:nudgeRightShortcut , app:nudgeUpShortcutapp:nudgeDownShortcut để chỉ định ID của chế độ xem con có thể lấy tiêu điểm, chế độ xem này sẽ được tập trung vào khi người dùng di chuyển theo một hướng nhất định. Để tìm hiểu thêm, hãy xem nội dung về các phím tắt di chuyển bên dưới.

    ( Android 11 QPR3, Android 11 Car, không được dùng nữa trong Android 12 ) app:nudgeShortcutapp:nudgeShortcutDirection chỉ hỗ trợ một phím tắt nudge.

  4. ( Android 11 QPR3, Android 11 Ô tô, Android 12 )
    Để cho phép xoay quanh FocusArea này, app:wrapAround có thể được đặt thành true . Điều này thường được sử dụng nhất khi các khung nhìn được sắp xếp theo hình tròn hoặc hình bầu dục.
  5. ( Android 11 QPR3, Android 11 Ô tô, Android 12 )
    Để điều chỉnh khoảng đệm của phần đánh dấu trong FocusArea này, hãy sử dụng app:highlightPaddingStart , app:highlightPaddingEnd , app:highlightPaddingTop , app:highlightPaddingBottom , app:highlightPaddingHorizontalapp:highlightPaddingVertical .
  6. ( Android 11 QPR3, Android 11 Ô tô, Android 12 )
    Để điều chỉnh giới hạn nhận biết của FocusArea này nhằm tìm mục tiêu thúc đẩy, hãy sử dụng app:startBoundOffset , app:endBoundOffset , app:topBoundOffset , app:bottomBoundOffset , app:horizontalBoundOffsetapp:verticalBoundOffset .
  7. ( Android 11 QPR3, Android 11 Ô tô, Android 12 )
    Để chỉ định rõ ràng ID của FocusArea (hoặc các khu vực) liền kề theo các hướng nhất định, hãy sử dụng app:nudgeLeft , app:nudgeRight , app:nudgeUpapp:nudgeDown . Sử dụng tính năng này khi tìm kiếm hình học được sử dụng theo mặc định không tìm thấy mục tiêu mong muốn.

Cú huých thường điều hướng giữa các khu vực tập trung. Nhưng với các phím tắt di chuyển, việc di chuyển đôi khi sẽ điều hướng lần đầu tiên trong FocusArea để người dùng có thể cần phải di chuyển hai lần để điều hướng đến FocusArea tiếp theo. Phím tắt di chuyển rất hữu ích khi FocusArea chứa một danh sách dài theo sau là Nút hành động nổi , như trong ví dụ bên dưới:

Di chuyển phím tắt
Hình 3. Phím tắt di chuyển

Nếu không có phím tắt di chuyển, người dùng sẽ phải xoay qua toàn bộ danh sách để đến FAB.

Tùy chỉnh điểm nhấn tiêu điểm

Như đã lưu ý ở trên, RotaryService xây dựng dựa trên khái niệm tập trung vào chế độ xem hiện có của khung công tác Android. Khi người dùng xoay và di chuyển, RotaryService sẽ di chuyển tiêu điểm xung quanh, tập trung vào một chế độ xem và làm mất tiêu điểm ở chế độ xem khác. Trong Android, khi chế độ xem được tập trung, nếu chế độ xem:

  • Đã chỉ định điểm nổi bật tiêu điểm của riêng mình, Android sẽ vẽ điểm nổi bật tiêu điểm của chế độ xem.
  • Không chỉ định điểm nổi bật tiêu điểm và điểm nổi bật tiêu điểm mặc định không bị tắt, Android sẽ vẽ điểm nổi bật tiêu điểm mặc định cho chế độ xem.

Các ứng dụng được thiết kế cho cảm ứng thường không chỉ định các điểm nổi bật cần lấy nét phù hợp.

Điểm nổi bật tiêu điểm mặc định được cung cấp bởi khung Android và có thể bị OEM ghi đè. Các nhà phát triển ứng dụng nhận được nó khi chủ đề họ đang sử dụng có nguồn gốc từ Theme.DeviceDefault .

Để có trải nghiệm người dùng nhất quán, hãy dựa vào tiêu điểm nổi bật mặc định bất cứ khi nào có thể. Nếu bạn cần điểm nhấn tiêu điểm có hình dạng tùy chỉnh (ví dụ: hình tròn hoặc hình viên thuốc) hoặc nếu bạn đang sử dụng một chủ đề không bắt nguồn từ Theme.DeviceDefault , hãy sử dụng tài nguyên thư viện xe hơi để chỉ định điểm nổi bật tiêu điểm của riêng bạn cho mỗi lượt xem.

Để chỉ định điểm đánh dấu tiêu điểm tùy chỉnh cho một chế độ xem, hãy thay đổi nền hoặc hình có thể vẽ ở nền trước của chế độ xem thành đối tượng có thể vẽ khác nhau khi chế độ xem được tập trung vào. Thông thường, bạn sẽ thay đổi nền. Đối tượng có thể vẽ sau đây, nếu được sử dụng làm nền cho chế độ xem hình vuông, sẽ tạo ra điểm nhấn tiêu điểm hình tròn:

<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 ) Các tham chiếu tài nguyên in đậm trong mẫu ở trên xác định các tài nguyên do thư viện car-ui-library xác định. OEM ghi đè những điều này để nhất quán với điểm nổi bật tiêu điểm mặc định mà họ chỉ định. Điều này đảm bảo rằng màu đánh dấu tiêu điểm, độ rộng nét, v.v. không thay đổi khi người dùng điều hướng giữa chế độ xem có điểm đánh dấu tiêu điểm tùy chỉnh và chế độ xem có điểm đánh dấu tiêu điểm mặc định. Mục cuối cùng là một gợn sóng được sử dụng để chạm. Các giá trị mặc định được sử dụng cho các tài nguyên in đậm xuất hiện như sau:

Giá trị mặc định cho tài nguyên in đậm
Hình 4. Giá trị mặc định cho tài nguyên in đậm

Ngoài ra, điểm nổi bật tiêu điểm tùy chỉnh được yêu cầu khi một nút được cung cấp màu nền đồng nhất để thu hút sự chú ý của người dùng, như trong ví dụ bên dưới. Điều này có thể làm cho điểm nhấn khó nhìn thấy. Trong trường hợp này, hãy chỉ định điểm đánh dấu tiêu điểm tùy chỉnh bằng cách sử dụng màu phụ :

Màu nền rắn
  • ( Android 11 QPR3, Android 11 Ô tô, 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

Ví dụ:

Tập trung, không ép buộcTập trung, ép
Tập trung, không ép buộc Tập trung, ép

Cuộn quay

Nếu ứng dụng của bạn sử dụng RecyclerView s, thì bạn NÊN sử dụng CarUiRecyclerView s thay thế. Điều này đảm bảo rằng giao diện người dùng của bạn nhất quán với những giao diện người dùng khác vì tùy chỉnh của OEM áp dụng cho tất cả các CarUiRecyclerView .

Nếu tất cả các thành phần trong danh sách của bạn đều có thể lấy tiêu điểm thì bạn không cần phải làm gì khác. Điều hướng xoay sẽ di chuyển tiêu điểm qua các phần tử trong danh sách và cuộn danh sách để hiển thị phần tử mới được lấy tiêu điểm.

( Android 11 QPR3, Android 11 Ô tô, Android 12 )
Nếu có sự kết hợp giữa các phần tử có thể lấy tiêu điểm và không thể lấy nét hoặc nếu tất cả các phần tử không thể lấy tiêu điểm, bạn có thể bật cuộn xoay, tính năng này cho phép người dùng sử dụng bộ điều khiển xoay để cuộn dần qua danh sách mà không bỏ qua các mục không thể lấy nét. Để bật cuộn xoay, hãy đặt thuộc tính app:rotaryScrollEnabled thành true .

( Android 11 QPR3, Android 11 Ô tô, Android 12 )
Bạn có thể bật tính năng cuộn xoay trong bất kỳ chế độ xem có thể cuộn nào, bao gồm av CarUiRecyclerView , bằng phương thức setRotaryScrollEnabled() trong CarUiUtils . Nếu bạn làm như vậy, bạn cần phải:

  • Làm cho chế độ xem có thể cuộn có thể lấy tiêu điểm để có thể tập trung vào chế độ xem đó khi không có chế độ xem con có thể lấy tiêu điểm nào của nó hiển thị,
  • Tắt tính năng đánh dấu tiêu điểm mặc định trên chế độ xem có thể cuộn bằng cách gọi setDefaultFocusHighlightEnabled(false) để chế độ xem có thể cuộn dường như không được lấy nét,
  • Đảm bảo rằng chế độ xem có thể cuộn được tập trung vào trước chế độ xem con cháu của nó bằng cách gọi setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS) .
  • Nghe MotionEvents bằng SOURCE_ROTARY_ENCODERAXIS_VSCROLL hoặc AXIS_HSCROLL để biểu thị khoảng cách cuộn và hướng (thông qua biển báo).

Khi tính năng cuộn xoay được bật trên CarUiRecyclerView và người dùng xoay đến khu vực không có chế độ xem có thể lấy tiêu điểm, thanh cuộn sẽ thay đổi từ màu xám sang màu xanh lam, như thể cho biết thanh cuộn đã được lấy tiêu điểm. Bạn có thể thực hiện một hiệu ứng tương tự nếu bạn muốn.

MotionEvent giống như các MotionEvent được tạo bởi con lăn trên chuột, ngoại trừ nguồn.

Chế độ thao tác trực tiếp

Thông thường, các thao tác di chuyển và xoay sẽ điều hướng qua giao diện người dùng, trong khi thao tác nhấn nút Trung tâm sẽ thực hiện hành động, mặc dù điều này không phải lúc nào cũng đúng. Ví dụ: nếu người dùng muốn điều chỉnh âm lượng cảnh báo, họ có thể sử dụng bộ điều khiển xoay để điều hướng đến thanh trượt âm lượng, nhấn nút Giữa, xoay bộ điều khiển để điều chỉnh âm lượng cảnh báo, sau đó nhấn nút Quay lại để quay lại điều hướng . Điều này được gọi là chế độ thao tác trực tiếp (DM) . Ở chế độ này, bộ điều khiển quay được sử dụng để tương tác trực tiếp với chế độ xem thay vì điều hướng.

Triển khai DM theo một trong hai cách. Nếu bạn chỉ cần xử lý thao tác xoay và chế độ xem bạn muốn thao tác sẽ phản hồi ACTION_SCROLL_FORWARDACTION_SCROLL_BACKWARD AccessibilityEvent s một cách thích hợp, hãy sử dụng cơ chế đơn giản . Nếu không, hãy sử dụng cơ chế nâng cao .

Cơ chế đơn giản là lựa chọn duy nhất trong cửa sổ hệ thống; ứng dụng có thể sử dụng một trong hai cơ chế.

Cơ chế đơn giản

( Android 11 QPR3, Android 11 Ô tô, Android 12 )
Ứng dụng của bạn nên gọi DirectManipulationHelper.setSupportsRotateDirectly(View view, boolean enable) . RotaryService nhận biết khi người dùng ở chế độ DM và chuyển sang chế độ DM khi người dùng nhấn nút Giữa trong khi chế độ xem được lấy nét. Khi ở chế độ DM, các thao tác xoay sẽ thực hiện ACTION_SCROLL_FORWARD hoặc ACTION_SCROLL_BACKWARD và thoát khỏi chế độ DM khi người dùng nhấn nút Quay lại. Cơ chế đơn giản chuyển đổi trạng thái đã chọn của chế độ xem khi vào và thoát chế độ DM.

Để cung cấp tín hiệu trực quan cho biết người dùng đang ở chế độ DM, hãy làm cho chế độ xem của bạn trông khác khi được chọn. Ví dụ: thay đổi nền khi android:state_selectedtrue .

Cơ chế nâng cao

Ứng dụng xác định thời điểm RotaryService vào và thoát khỏi chế độ DM. Để có trải nghiệm người dùng nhất quán, việc nhấn nút Giữa với chế độ xem DM được tập trung sẽ chuyển sang chế độ DM và nút Quay lại sẽ thoát khỏi chế độ DM. Nếu nút Giữa và/hoặc dịch chuyển không được sử dụng, chúng có thể là những cách khác để thoát khỏi chế độ DM. Đối với các ứng dụng như Bản đồ, có thể sử dụng nút đại diện cho DM để vào chế độ DM.

Để hỗ trợ chế độ DM nâng cao, chế độ xem:

  1. ( Android 11 QPR3, Android 11 Car, Android 12 ) PHẢI nghe sự kiện KEYCODE_DPAD_CENTER để vào chế độ DM và nghe sự kiện KEYCODE_BACK để thoát khỏi chế độ DM, gọi DirectManipulationHelper.enableDirectManipulationMode() trong từng trường hợp. Để lắng nghe những sự kiện này, hãy thực hiện một trong các thao tác sau:
    • Đăng ký OnKeyListener .
    • hoặc,
    • Mở rộng chế độ xem và sau đó ghi đè phương thức dispatchKeyEvent() của nó.
  2. NÊN lắng nghe các sự kiện chuyển động ( KEYCODE_DPAD_UP , KEYCODE_DPAD_DOWN , KEYCODE_DPAD_LEFT hoặc KEYCODE_DPAD_RIGHT ) nếu chế độ xem cần xử lý các chuyển động.
  3. NÊN nghe MotionEvent s và nhận số vòng quay trong AXIS_SCROLL nếu chế độ xem muốn xử lý xoay vòng. Có nhiều hướng khác nhau để làm điều đó:
    1. Đăng ký OnGenericMotionListener .
    2. Mở rộng chế độ xem và ghi đè phương thức dispatchTouchEvent() của nó.
  4. Để tránh bị kẹt ở chế độ DM, PHẢI thoát khỏi chế độ DM khi Phân đoạn hoặc Hoạt động mà chế độ xem thuộc về không tương tác.
  5. NÊN cung cấp tín hiệu trực quan để cho biết rằng chế độ xem đang ở chế độ DM.

Mẫu chế độ xem tùy chỉnh sử dụng chế độ DM để xoay và thu phóng bản đồ được cung cấp bên dưới:

/** 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(); }

Bạn có thể tìm thấy nhiều ví dụ khác trong dự án RotaryPlayground .

Chế độ xem hoạt động

Khi sử dụng Chế độ xem hoạt động:

  • ActivityView không thể lấy nét được.
  • ( Android 11 QPR3, Android 11 Car, không dùng nữa trong Android 11 )
    Nội dung của Chế ActivityView PHẢI chứa FocusParkingView làm chế độ xem có thể lấy tiêu điểm đầu tiên và thuộc tính app:shouldRestoreFocus của nó PHẢI là false .
  • Nội dung của ActivityView không được có chế độ xem android:focusByDefault .

Đối với người dùng, Chế độ xem hoạt động sẽ không ảnh hưởng đến việc điều hướng ngoại trừ các khu vực trọng tâm không thể mở rộng Chế độ xem hoạt động. Nói cách khác, bạn không thể có một khu vực tập trung duy nhất có nội dung bên trong bên ngoài ActivityView . Nếu bạn không thêm bất kỳ FocusAreas nào vào ActivityView của mình thì phần gốc của hệ thống phân cấp chế độ xem trong ActivityView sẽ được coi là khu vực tiêu điểm tiềm ẩn.

Các nút hoạt động khi nhấn giữ

Hầu hết các nút đều gây ra một số hành động khi được nhấp vào. Thay vào đó, một số nút hoạt động khi được nhấn giữ. Ví dụ: các nút Chuyển tiếp nhanh và Tua lại thường hoạt động khi được nhấn giữ. Để làm cho các nút như vậy hỗ trợ quay, hãy lắng nghe KEYCODE_DPAD_CENTER KeyEvents như sau:

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;
});

Trong đó mRunnable thực hiện một hành động (chẳng hạn như tua lại) và tự lên lịch để chạy sau một khoảng thời gian trì hoãn.

Chế độ cảm ứng

Người dùng có thể sử dụng bộ điều khiển quay để tương tác với bộ phận đầu trong ô tô theo hai cách, bằng cách sử dụng bộ điều khiển quay hoặc bằng cách chạm vào màn hình. Khi sử dụng bộ điều khiển quay, một trong các chế độ xem có thể lấy tiêu điểm sẽ được tô sáng. Khi chạm vào màn hình, điểm nhấn tiêu điểm không xuất hiện. Người dùng có thể chuyển đổi giữa các chế độ nhập này bất kỳ lúc nào:

  • Xoay → chạm. Khi người dùng chạm vào màn hình, điểm sáng tiêu điểm sẽ biến mất.
  • Chạm vào → xoay. Khi người dùng di chuyển, xoay hoặc nhấn nút Giữa, điểm đánh dấu tiêu điểm sẽ xuất hiện.

Các nút Quay lại và Trang chủ không có tác dụng đối với chế độ nhập liệu.

Xoay quanh khái niệm chế độ cảm ứng hiện có của Android. Bạn có thể sử dụng View.isInTouchMode() để xác định chế độ nhập mà người dùng đang sử dụng. Bạn có thể sử dụng OnTouchModeChangeListener để lắng nghe các thay đổi. Mặc dù điều này có thể được sử dụng để tùy chỉnh giao diện người dùng của bạn cho chế độ nhập hiện tại, nhưng hãy tránh mọi thay đổi lớn vì chúng có thể gây bối rối.

Xử lý sự cố

Trong ứng dụng được thiết kế cho cảm ứng, thông thường có các chế độ xem có thể lấy tiêu điểm lồng nhau. Ví dụ: có thể có FrameLayout xung quanh ImageButton , cả hai đều có thể lấy tiêu điểm. Điều này không gây hại cho cảm ứng nhưng có thể dẫn đến trải nghiệm người dùng kém khi quay vì người dùng phải xoay bộ điều khiển hai lần để chuyển sang chế độ xem tương tác tiếp theo. Để có trải nghiệm tốt cho người dùng, Google khuyên bạn nên đặt tiêu điểm cho chế độ xem bên ngoài hoặc chế độ xem bên trong chứ không phải cả hai.

Nếu một nút hoặc công tắc mất tiêu điểm khi nhấn qua bộ điều khiển quay, một trong các điều kiện sau có thể áp dụng:

  • Nút hoặc công tắc đang bị vô hiệu hóa (trong thời gian ngắn hoặc vô thời hạn) do nút được nhấn. Trong cả hai trường hợp, có hai cách để giải quyết vấn đề này:
    • Để trạng thái android:enabledtrue và sử dụng trạng thái tùy chỉnh để chuyển nút hoặc chuyển đổi sang màu xám như được mô tả trong Trạng thái tùy chỉnh .
    • Sử dụng vùng chứa để bao quanh nút hoặc công tắc và làm cho vùng chứa có thể lấy tiêu điểm thay vì nút hoặc công tắc. (Trình nghe nhấp chuột phải ở trên vùng chứa.)
  • Nút hoặc công tắc đang được thay thế. Ví dụ: hành động được thực hiện khi nhấn nút hoặc bật công tắc có thể kích hoạt làm mới các hành động sẵn có khiến các nút mới thay thế các nút hiện có. Có hai cách để giải quyết vấn đề này:
    • Thay vì tạo nút hoặc công tắc mới, hãy đặt biểu tượng và/hoặc văn bản của nút hoặc công tắc hiện có.
    • Như trên, thêm vùng chứa có thể lấy tiêu điểm xung quanh nút hoặc công tắc.

quaySân chơi

RotaryPlayground là một ứng dụng tham khảo cho quay. Sử dụng nó để tìm hiểu cách tích hợp các tính năng quay vào ứng dụng của bạn. RotaryPlayground được bao gồm trong các bản dựng trình mô phỏng và trong các bản dựng dành cho thiết bị chạy Android Automotive OS (AAOS).

  • Kho lưu trữ RotaryPlayground : packages/apps/Car/tests/RotaryPlayground/
  • Phiên bản: Android 11 QPR3, Android 11 Car và Android 12

Ứng dụng RotaryPlayground hiển thị các tab sau ở bên trái:

  • Thẻ. Kiểm tra việc điều hướng xung quanh các khu vực trọng tâm, bỏ qua các phần tử không thể lấy nét và nhập văn bản.
  • Thao tác trực tiếp. Kiểm tra các widget hỗ trợ chế độ thao tác trực tiếp đơn giản và nâng cao. Tab này dành riêng cho thao tác trực tiếp trong cửa sổ ứng dụng.
  • Thao tác giao diện người dùng Sys. Kiểm tra các tiện ích hỗ trợ thao tác trực tiếp trong cửa sổ hệ thống chỉ hỗ trợ chế độ thao tác trực tiếp đơn giản.
  • Lưới. Kiểm tra điều hướng xoay kiểu z bằng cách cuộn.
  • Thông báo. Kiểm tra việc đưa vào và ra khỏi thông báo cảnh báo.
  • Cuộn. Kiểm tra việc cuộn qua sự kết hợp giữa nội dung có thể tập trung và không thể tập trung.
  • WebView. Kiểm tra việc điều hướng qua các liên kết trong WebView .
  • FocusArea tùy chỉnh Kiểm tra tùy chỉnh FocusArea :
    • Quấn quanh.
    • android:focusedByDefaultapp:defaultFocus
    • .
    • Mục tiêu thúc đẩy rõ ràng.
    • Di chuyển các phím tắt.
    • FocusArea không có chế độ xem có thể lấy nét.
,

Tài liệu sau đây dành cho các nhà phát triển ứng dụng.

Để làm cho ứng dụng của bạn quay vòng, bạn PHẢI:

  1. Đặt FocusParkingView trong bố cục hoạt động tương ứng.
  2. Đảm bảo các chế độ xem có thể (hoặc không) có thể lấy tiêu điểm.
  3. Sử dụng FocusArea để bao quanh tất cả các chế độ xem có thể lấy tiêu điểm của bạn, ngoại trừ FocusParkingView .

Mỗi tác vụ này được trình bày chi tiết bên dưới, sau khi bạn thiết lập môi trường của mình để phát triển các ứng dụng hỗ trợ quay.

Thiết lập bộ điều khiển quay

Trước khi có thể bắt đầu phát triển các ứng dụng hỗ trợ quay, bạn cần có bộ điều khiển quay hoặc thiết bị thay thế. Bạn có các tùy chọn được mô tả bên dưới.

Giả lập

source build/envsetup.sh && lunch car_x86_64-userdebug
m -j
emulator -wipe-data -no-snapshot -writable-system

Bạn cũng có thể sử dụng aosp_car_x86_64-userdebug .

Để truy cập bộ điều khiển quay mô phỏng:

  1. Nhấn vào ba dấu chấm ở cuối thanh công cụ:

    Truy cập bộ điều khiển quay mô phỏng
    Hình 1. Bộ điều khiển quay mô phỏng Access
  2. Chọn Vòng quay ô tô trong cửa sổ điều khiển mở rộng:

    Chọn Vòng quay ô tô
    Hình 2. Chọn Vòng quay ô tô

bàn phím USB

  • Cắm bàn phím USB vào thiết bị chạy Android Automotive OS (AAOS). Trong một số trường hợp, điều này ngăn bàn phím ảo xuất hiện.
  • Sử dụng userdebug hoặc eng build.
  • Bật tính năng lọc sự kiện quan trọng:
    adb shell settings put secure android.car.ROTARY_KEY_EVENT_FILTER 1
    
  • Xem bảng bên dưới để tìm key tương ứng cho từng hành động:
    Chìa khóa Hành động quay
    Q Xoay ngược chiều kim đồng hồ
    E Xoay theo chiều kim đồng hồ
    MỘT Di chuyển sang trái
    D Di chuyển sang phải
    W Đẩy lên
    S Đẩy xuống
    F hoặc dấu phẩy Nút giữa
    R hoặc Esc Nút quay lại

lệnh ADB

Bạn có thể sử dụng lệnh car_service để đưa vào các sự kiện đầu vào quay. Các lệnh này có thể chạy trên các thiết bị chạy Android Automotive OS (AAOS) hoặc trên trình mô phỏng.

lệnh car_service Đầu vào quay
adb shell cmd car_service inject-rotary Xoay ngược chiều kim đồng hồ
adb shell cmd car_service inject-rotary -c true Xoay theo chiều kim đồng hồ
adb shell cmd car_service inject-rotary -dt 100 50 Xoay ngược chiều kim đồng hồ nhiều lần (cách đây 100 mili giây và cách đây 50 mili giây)
adb shell cmd car_service inject-key 282 Di chuyển sang trái
adb shell cmd car_service inject-key 283 Di chuyển sang phải
adb shell cmd car_service inject-key 280 Đẩy lên
adb shell cmd car_service inject-key 281 Đẩy xuống
adb shell cmd car_service inject-key 23 Bấm nút giữa
adb shell input keyevent inject-key 4 Bấm nút quay lại

Bộ điều khiển quay OEM

Khi phần cứng bộ điều khiển quay của bạn hoạt động, đây là tùy chọn thực tế nhất. Nó đặc biệt hữu ích để thử nghiệm khả năng quay nhanh.

Tập TrungBãi Đậu XeXem

FocusParkingView là chế độ xem trong suốt trong Thư viện UI ô tô (car-ui-library) . RotaryService sử dụng nó để hỗ trợ điều hướng bộ điều khiển quay. FocusParkingView phải là chế độ xem có thể lấy tiêu điểm đầu tiên trong bố cục. Nó phải được đặt bên ngoài tất cả FocusArea s. Mỗi cửa sổ phải có một FocusParkingView . Nếu bạn đang sử dụng bố cục cơ sở thư viện ô tô-ui-library có chứa FocusParkingView thì bạn không cần thêm FocusParkingView khác. Dưới đây là ví dụ về FocusParkingView trong 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>

Dưới đây là những lý do bạn cần FocusParkingView :

  1. Android không tự động xóa tiêu điểm khi tiêu điểm được đặt trong một cửa sổ khác. Nếu bạn cố gắng xóa tiêu điểm trong cửa sổ trước, Android sẽ lấy nét lại chế độ xem trong cửa sổ đó, dẫn đến hai cửa sổ được lấy tiêu điểm cùng lúc. Việc thêm FocusParkingView vào mỗi cửa sổ có thể khắc phục sự cố này. Chế độ xem này trong suốt và phần đánh dấu tiêu điểm mặc định của nó bị tắt, do đó nó không hiển thị với người dùng cho dù có được lấy nét hay không. Nó có thể lấy tiêu điểm để RotaryService có thể đặt tiêu điểm vào đó để loại bỏ phần đánh dấu tiêu điểm.
  2. Nếu chỉ có một FocusArea trong cửa sổ hiện tại, việc xoay bộ điều khiển trong FocusArea sẽ khiến RotaryService di chuyển tiêu điểm từ chế độ xem bên phải sang chế độ xem bên trái (và ngược lại). Việc thêm chế độ xem này vào mỗi cửa sổ có thể khắc phục được sự cố. Khi RotaryService xác định mục tiêu tiêu điểm là FocusParkingView , nó có thể xác định việc bao bọc sắp xảy ra tại thời điểm đó nó tránh được việc bao quanh bằng cách không di chuyển tiêu điểm.
  3. Khi điều khiển xoay khởi chạy một ứng dụng, Android sẽ tập trung vào chế độ xem có thể lấy tiêu điểm đầu tiên, luôn là FocusParkingView . FocusParkingView xác định chế độ xem tối ưu để lấy nét và sau đó áp dụng tiêu điểm.

Chế độ xem có thể tập trung

RotaryService được xây dựng dựa trên khái niệm tập trung vào chế độ xem hiện có của khung Android, có từ thời điện thoại có bàn phím vật lý và D-pad. Thuộc tính android:nextFocusForward hiện tại được tái sử dụng cho tính năng quay (xem tùy chỉnh FocusArea ), nhưng android:nextFocusLeft , android:nextFocusRight , android:nextFocusUpandroid:nextFocusDown thì không.

RotaryService chỉ tập trung vào các chế độ xem có thể lấy tiêu điểm. Một số chế độ xem, chẳng hạn như Button s, thường có thể lấy tiêu điểm. Những cái khác, chẳng hạn như TextView s và ViewGroup s, thường không có. Các chế độ xem có thể nhấp sẽ tự động có thể lấy tiêu điểm và các chế độ xem sẽ tự động có thể nhấp khi chúng có trình xử lý lượt nhấp. Nếu logic tự động này mang lại khả năng lấy nét mong muốn thì bạn không cần đặt rõ ràng khả năng lấy nét của chế độ xem. Nếu logic tự động không mang lại khả năng lấy nét như mong muốn, hãy đặt thuộc android:focusable thành true hoặc false hoặc đặt khả năng lấy nét của chế độ xem theo chương trình với View.setFocusable(boolean) . Để RotaryService tập trung vào nó, chế độ xem PHẢI đáp ứng các yêu cầu sau:

  • Có thể lấy nét
  • Đã bật
  • Dễ thấy
  • Có giá trị khác 0 cho chiều rộng và chiều cao

Nếu chế độ xem không đáp ứng tất cả các yêu cầu này, chẳng hạn như nút có thể lấy tiêu điểm nhưng bị vô hiệu hóa, thì người dùng không thể sử dụng điều khiển xoay để lấy tiêu điểm vào chế độ xem đó. Nếu bạn muốn tập trung vào chế độ xem bị vô hiệu hóa, hãy cân nhắc sử dụng trạng thái tùy chỉnh thay vì android:state_enabled để kiểm soát cách chế độ xem xuất hiện mà không cho biết rằng Android nên coi chế độ xem đó bị vô hiệu hóa. Ứng dụng của bạn có thể thông báo cho người dùng lý do chế độ xem bị tắt khi nhấn vào. Phần tiếp theo giải thích cách thực hiện việc này.

Trạng thái tùy chỉnh

Để thêm trạng thái tùy chỉnh:

  1. Để thêm thuộc tính tùy chỉnh vào chế độ xem của bạn. Ví dụ: để thêm trạng thái tùy chỉnh state_rotary_enabled vào lớp chế độ xem CustomView , hãy sử dụng:
    <declare-styleable name="CustomView">
        <attr name="state_rotary_enabled" format="boolean" />
    </declare-styleable>
    
  2. Để theo dõi trạng thái này, hãy thêm một biến thể hiện vào chế độ xem của bạn cùng với các phương thức truy cập:
    private boolean mRotaryEnabled;
    public boolean getRotaryEnabled() { return mRotaryEnabled; }
    public void setRotaryEnabled(boolean rotaryEnabled) {
        mRotaryEnabled = rotaryEnabled;
    }
    
  3. Để đọc giá trị thuộc tính của bạn khi chế độ xem của bạn được tạo:
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView);
    mRotaryEnabled = a.getBoolean(R.styleable.CustomView_state_rotary_enabled);
    
  4. Trong lớp dạng xem của bạn, hãy ghi đè phương thức onCreateDrawableState() rồi thêm trạng thái tùy chỉnh khi thích hợp. Ví dụ:
    @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. Làm cho trình xử lý nhấp chuột của chế độ xem của bạn hoạt động khác nhau tùy thuộc vào trạng thái của nó. Ví dụ: trình xử lý nhấp chuột có thể không làm gì hoặc nó có thể bật lên một lời chúc mừng khi mRotaryEnabled false .
  6. Để làm cho nút có vẻ bị tắt, trong nền có thể vẽ được của chế độ xem của bạn, hãy sử dụng app:state_rotary_enabled thay vì android:state_enabled . Nếu chưa có thì bạn cần thêm:
    xmlns:app="http://schemas.android.com/apk/res-auto"
    
  7. Nếu chế độ xem của bạn bị tắt trong bất kỳ bố cục nào, hãy thay thế android:enabled="false" bằng app:state_rotary_enabled="false" rồi thêm vùng tên app , như trên.
  8. Nếu chế độ xem của bạn bị tắt theo chương trình, hãy thay thế lệnh gọi setEnabled() bằng lệnh gọi setRotaryEnabled() .

Khu vực tập trung

Sử dụng FocusAreas để phân vùng các chế độ xem có thể lấy tiêu điểm thành các khối nhằm giúp điều hướng dễ dàng hơn và nhất quán với các ứng dụng khác. Ví dụ: nếu ứng dụng của bạn có thanh công cụ thì thanh công cụ đó phải nằm trong một FocusArea riêng biệt với phần còn lại của ứng dụng. Thanh tab và các thành phần điều hướng khác cũng phải được tách biệt khỏi phần còn lại của ứng dụng. Các danh sách lớn thường phải có FocusArea riêng. Nếu không, người dùng phải xoay qua toàn bộ danh sách để truy cập một số chế độ xem.

FocusArea là một lớp con của LinearLayout trong thư viện car-ui. Khi tính năng này được bật, FocusArea sẽ nổi bật khi một trong các thành phần con của nó được lấy nét. Để tìm hiểu thêm, hãy xem Tùy chỉnh tiêu điểm nổi bật .

Khi tạo khối điều hướng trong tệp bố cục, nếu bạn định sử dụng LinearLayout làm vùng chứa cho khối đó, hãy sử dụng FocusArea thay thế. Nếu không, hãy bọc khối trong FocusArea .

KHÔNG lồng FocusArea vào FocusArea khác. Làm như vậy sẽ dẫn đến hành vi điều hướng không xác định. Đảm bảo rằng tất cả các chế độ xem có thể lấy tiêu điểm đều được lồng trong FocusArea .

Một ví dụ về FocusArea trong RotaryPlayground được hiển thị bên dưới:

<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 hoạt động như sau:

  1. Khi xử lý các hành động xoay và di chuyển, RotaryService sẽ tìm kiếm các phiên bản của FocusArea trong hệ thống phân cấp chế độ xem.
  2. Khi nhận được sự kiện xoay vòng, RotaryService sẽ chuyển tiêu điểm sang một Chế độ xem khác có thể lấy tiêu điểm trong cùng FocusArea .
  3. Khi nhận được một sự kiện nâng cao, RotaryService sẽ di chuyển tiêu điểm sang một chế độ xem khác có thể lấy tiêu điểm ở một FocusArea khác (thường liền kề).

Nếu bạn không bao gồm bất kỳ FocusAreas trong bố cục của mình thì chế độ xem gốc sẽ được coi là vùng lấy nét ngầm. Người dùng không thể di chuyển để điều hướng trong ứng dụng. Thay vào đó, chúng sẽ xoay qua tất cả các chế độ xem có thể lấy tiêu điểm, điều này có thể phù hợp với các hộp thoại.

Tùy chỉnh vùng lấy nét

Hai thuộc tính Chế độ xem tiêu chuẩn có thể được sử dụng để tùy chỉnh điều hướng quay:

  • android:nextFocusForward cho phép nhà phát triển ứng dụng chỉ định thứ tự xoay trong vùng trọng tâm. Đây là thuộc tính tương tự được sử dụng để kiểm soát thứ tự Tab cho điều hướng bàn phím. KHÔNG sử dụng thuộc tính này để tạo vòng lặp. Thay vào đó, hãy sử dụng app:wrapAround (xem bên dưới) để tạo vòng lặp.
  • android:focusedByDefault cho phép nhà phát triển ứng dụng chỉ định chế độ xem tiêu điểm mặc định trong cửa sổ. KHÔNG sử dụng thuộc tính này và app:defaultFocus (xem bên dưới) trong cùng một FocusArea .

FocusArea cũng xác định một số thuộc tính để tùy chỉnh điều hướng quay. Không thể tùy chỉnh các vùng tiêu điểm ngầm định bằng các thuộc tính này.

  1. ( Android 11 QPR3, Android 11 Ô tô, Android 12 )
    app:defaultFocus có thể được sử dụng để chỉ định ID của chế độ xem con có thể lấy tiêu điểm, chế độ xem này sẽ được tập trung vào khi người dùng di chuyển tới FocusArea này.
  2. ( Android 11 QPR3, Android 11 Ô tô, Android 12 )
    app:defaultFocusOverridesHistory có thể được đặt thành true để làm cho chế độ xem được chỉ định ở trên lấy tiêu điểm ngay cả khi có lịch sử để biểu thị một chế độ xem khác trong FocusArea này đã được tập trung vào.
  3. ( Android 12 )
    Sử dụng app:nudgeLeftShortcut , app:nudgeRightShortcut , app:nudgeUpShortcutapp:nudgeDownShortcut để chỉ định ID của chế độ xem con có thể lấy tiêu điểm, chế độ xem này sẽ được tập trung vào khi người dùng di chuyển theo một hướng nhất định. Để tìm hiểu thêm, hãy xem nội dung về các phím tắt di chuyển bên dưới.

    ( Android 11 QPR3, Android 11 Car, không được dùng nữa trong Android 12 ) app:nudgeShortcutapp:nudgeShortcutDirection chỉ hỗ trợ một phím tắt nudge.

  4. ( Android 11 QPR3, Android 11 Ô tô, Android 12 )
    Để cho phép xoay quanh FocusArea này, app:wrapAround có thể được đặt thành true . Điều này thường được sử dụng nhất khi các khung nhìn được sắp xếp theo hình tròn hoặc hình bầu dục.
  5. ( Android 11 QPR3, Android 11 Ô tô, Android 12 )
    Để điều chỉnh khoảng đệm của phần đánh dấu trong FocusArea này, hãy sử dụng app:highlightPaddingStart , app:highlightPaddingEnd , app:highlightPaddingTop , app:highlightPaddingBottom , app:highlightPaddingHorizontalapp:highlightPaddingVertical .
  6. ( Android 11 QPR3, Android 11 Ô tô, Android 12 )
    Để điều chỉnh giới hạn nhận biết của FocusArea này nhằm tìm mục tiêu thúc đẩy, hãy sử dụng app:startBoundOffset , app:endBoundOffset , app:topBoundOffset , app:bottomBoundOffset , app:horizontalBoundOffsetapp:verticalBoundOffset .
  7. ( Android 11 QPR3, Android 11 Ô tô, Android 12 )
    Để chỉ định rõ ràng ID của FocusArea (hoặc các khu vực) liền kề theo các hướng nhất định, hãy sử dụng app:nudgeLeft , app:nudgeRight , app:nudgeUpapp:nudgeDown . Sử dụng tính năng này khi tìm kiếm hình học được sử dụng theo mặc định không tìm thấy mục tiêu mong muốn.

Cú huých thường điều hướng giữa các khu vực tập trung. Nhưng với các phím tắt di chuyển, việc di chuyển đôi khi sẽ điều hướng lần đầu tiên trong FocusArea để người dùng có thể cần phải di chuyển hai lần để điều hướng đến FocusArea tiếp theo. Phím tắt di chuyển rất hữu ích khi FocusArea chứa một danh sách dài theo sau là Nút hành động nổi , như trong ví dụ bên dưới:

Di chuyển phím tắt
Hình 3. Phím tắt di chuyển

Nếu không có phím tắt di chuyển, người dùng sẽ phải xoay qua toàn bộ danh sách để đến FAB.

Tùy chỉnh điểm nhấn tiêu điểm

Như đã lưu ý ở trên, RotaryService xây dựng dựa trên khái niệm tập trung vào chế độ xem hiện có của khung công tác Android. Khi người dùng xoay và di chuyển, RotaryService sẽ di chuyển tiêu điểm xung quanh, tập trung vào một chế độ xem và làm mất tiêu điểm ở chế độ xem khác. Trong Android, khi chế độ xem được tập trung, nếu chế độ xem:

  • Đã chỉ định điểm nổi bật tiêu điểm của riêng mình, Android sẽ vẽ điểm nổi bật tiêu điểm của chế độ xem.
  • Không chỉ định điểm nổi bật tiêu điểm và điểm nổi bật tiêu điểm mặc định không bị tắt, Android sẽ vẽ điểm nổi bật tiêu điểm mặc định cho chế độ xem.

Các ứng dụng được thiết kế cho cảm ứng thường không chỉ định các điểm nổi bật cần lấy nét phù hợp.

Điểm nổi bật tiêu điểm mặc định được cung cấp bởi khung Android và có thể bị OEM ghi đè. Các nhà phát triển ứng dụng nhận được nó khi chủ đề họ đang sử dụng có nguồn gốc từ Theme.DeviceDefault .

Để có trải nghiệm người dùng nhất quán, hãy dựa vào tiêu điểm nổi bật mặc định bất cứ khi nào có thể. Nếu bạn cần điểm nhấn tiêu điểm có hình dạng tùy chỉnh (ví dụ: hình tròn hoặc hình viên thuốc) hoặc nếu bạn đang sử dụng một chủ đề không bắt nguồn từ Theme.DeviceDefault , hãy sử dụng tài nguyên thư viện xe hơi để chỉ định điểm nổi bật tiêu điểm của riêng bạn cho mỗi lượt xem.

Để chỉ định điểm đánh dấu tiêu điểm tùy chỉnh cho một chế độ xem, hãy thay đổi nền hoặc hình có thể vẽ ở nền trước của chế độ xem thành đối tượng có thể vẽ khác nhau khi chế độ xem được tập trung vào. Thông thường, bạn sẽ thay đổi nền. Đối tượng có thể vẽ sau đây, nếu được sử dụng làm nền cho chế độ xem hình vuông, sẽ tạo ra điểm nhấn tiêu điểm hình tròn:

<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 ) Các tham chiếu tài nguyên in đậm trong mẫu ở trên xác định các tài nguyên do thư viện car-ui-library xác định. OEM ghi đè những điều này để nhất quán với điểm nổi bật tiêu điểm mặc định mà họ chỉ định. Điều này đảm bảo rằng màu đánh dấu tiêu điểm, độ rộng nét, v.v. không thay đổi khi người dùng điều hướng giữa chế độ xem có điểm đánh dấu tiêu điểm tùy chỉnh và chế độ xem có điểm đánh dấu tiêu điểm mặc định. Mục cuối cùng là một gợn sóng được sử dụng để chạm. Các giá trị mặc định được sử dụng cho các tài nguyên in đậm xuất hiện như sau:

Giá trị mặc định cho tài nguyên in đậm
Hình 4. Giá trị mặc định cho tài nguyên in đậm

Ngoài ra, điểm nổi bật tiêu điểm tùy chỉnh được yêu cầu khi một nút được cung cấp màu nền đồng nhất để thu hút sự chú ý của người dùng, như trong ví dụ bên dưới. Điều này có thể làm cho điểm nhấn khó nhìn thấy. Trong trường hợp này, hãy chỉ định điểm đánh dấu tiêu điểm tùy chỉnh bằng cách sử dụng màu phụ :

Màu nền rắn
  • ( Android 11 QPR3, Android 11 Ô tô, 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

Ví dụ:

Tập trung, không ép buộcTập trung, ép
Tập trung, không ép buộc Tập trung, ép

Cuộn quay

Nếu ứng dụng của bạn sử dụng RecyclerView s, thì bạn NÊN sử dụng CarUiRecyclerView s thay thế. Điều này đảm bảo rằng giao diện người dùng của bạn nhất quán với những giao diện người dùng khác vì tùy chỉnh của OEM áp dụng cho tất cả các CarUiRecyclerView .

Nếu tất cả các thành phần trong danh sách của bạn đều có thể lấy tiêu điểm thì bạn không cần phải làm gì khác. Điều hướng xoay sẽ di chuyển tiêu điểm qua các phần tử trong danh sách và cuộn danh sách để hiển thị phần tử mới được lấy tiêu điểm.

( Android 11 QPR3, Android 11 Ô tô, Android 12 )
Nếu có sự kết hợp giữa các phần tử có thể lấy tiêu điểm và không thể lấy nét hoặc nếu tất cả các phần tử không thể lấy tiêu điểm, bạn có thể bật cuộn xoay, tính năng này cho phép người dùng sử dụng bộ điều khiển xoay để cuộn dần qua danh sách mà không bỏ qua các mục không thể lấy nét. Để bật cuộn xoay, hãy đặt thuộc tính app:rotaryScrollEnabled thành true .

( Android 11 QPR3, Android 11 Ô tô, Android 12 )
Bạn có thể bật tính năng cuộn xoay trong bất kỳ chế độ xem có thể cuộn nào, bao gồm av CarUiRecyclerView , bằng phương thức setRotaryScrollEnabled() trong CarUiUtils . Nếu bạn làm như vậy, bạn cần phải:

  • Làm cho chế độ xem có thể cuộn có thể lấy tiêu điểm để có thể tập trung vào chế độ xem đó khi không có chế độ xem con có thể lấy tiêu điểm nào của nó hiển thị,
  • Tắt tính năng đánh dấu tiêu điểm mặc định trên chế độ xem có thể cuộn bằng cách gọi setDefaultFocusHighlightEnabled(false) để chế độ xem có thể cuộn dường như không được lấy nét,
  • Đảm bảo rằng chế độ xem có thể cuộn được tập trung vào trước chế độ xem con cháu của nó bằng cách gọi setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS) .
  • Nghe MotionEvents bằng SOURCE_ROTARY_ENCODERAXIS_VSCROLL hoặc AXIS_HSCROLL để biểu thị khoảng cách cuộn và hướng (thông qua biển báo).

Khi tính năng cuộn xoay được bật trên CarUiRecyclerView và người dùng xoay đến khu vực không có chế độ xem có thể lấy tiêu điểm, thanh cuộn sẽ thay đổi từ màu xám sang màu xanh lam, như thể cho biết thanh cuộn đã được lấy tiêu điểm. Bạn có thể thực hiện một hiệu ứng tương tự nếu bạn muốn.

MotionEvent giống như các MotionEvent được tạo bởi con lăn trên chuột, ngoại trừ nguồn.

Chế độ thao tác trực tiếp

Thông thường, các thao tác di chuyển và xoay sẽ điều hướng qua giao diện người dùng, trong khi thao tác nhấn nút Trung tâm sẽ thực hiện hành động, mặc dù điều này không phải lúc nào cũng đúng. Ví dụ: nếu người dùng muốn điều chỉnh âm lượng cảnh báo, họ có thể sử dụng bộ điều khiển xoay để điều hướng đến thanh trượt âm lượng, nhấn nút Giữa, xoay bộ điều khiển để điều chỉnh âm lượng cảnh báo, sau đó nhấn nút Quay lại để quay lại điều hướng . Điều này được gọi là chế độ thao tác trực tiếp (DM) . Ở chế độ này, bộ điều khiển quay được sử dụng để tương tác trực tiếp với chế độ xem thay vì điều hướng.

Triển khai DM theo một trong hai cách. Nếu bạn chỉ cần xử lý thao tác xoay và chế độ xem bạn muốn thao tác sẽ phản hồi ACTION_SCROLL_FORWARDACTION_SCROLL_BACKWARD AccessibilityEvent s một cách thích hợp, hãy sử dụng cơ chế đơn giản . Nếu không, hãy sử dụng cơ chế nâng cao .

Cơ chế đơn giản là lựa chọn duy nhất trong cửa sổ hệ thống; ứng dụng có thể sử dụng một trong hai cơ chế.

Cơ chế đơn giản

( Android 11 QPR3, Android 11 Ô tô, Android 12 )
Ứng dụng của bạn nên gọi DirectManipulationHelper.setSupportsRotateDirectly(View view, boolean enable) . RotaryService nhận biết khi người dùng ở chế độ DM và chuyển sang chế độ DM khi người dùng nhấn nút Giữa trong khi chế độ xem được lấy nét. Khi ở chế độ DM, các thao tác xoay sẽ thực hiện ACTION_SCROLL_FORWARD hoặc ACTION_SCROLL_BACKWARD và thoát khỏi chế độ DM khi người dùng nhấn nút Quay lại. Cơ chế đơn giản chuyển đổi trạng thái đã chọn của chế độ xem khi vào và thoát chế độ DM.

Để cung cấp tín hiệu trực quan cho biết người dùng đang ở chế độ DM, hãy làm cho chế độ xem của bạn trông khác khi được chọn. Ví dụ: thay đổi nền khi android:state_selectedtrue .

Cơ chế nâng cao

Ứng dụng xác định thời điểm RotaryService vào và thoát khỏi chế độ DM. Để có trải nghiệm người dùng nhất quán, việc nhấn nút Giữa với chế độ xem DM được tập trung sẽ chuyển sang chế độ DM và nút Quay lại sẽ thoát khỏi chế độ DM. Nếu nút Giữa và/hoặc dịch chuyển không được sử dụng, chúng có thể là những cách khác để thoát khỏi chế độ DM. Đối với các ứng dụng như Bản đồ, có thể sử dụng nút đại diện cho DM để vào chế độ DM.

Để hỗ trợ chế độ DM nâng cao, chế độ xem:

  1. ( Android 11 QPR3, Android 11 Car, Android 12 ) PHẢI nghe sự kiện KEYCODE_DPAD_CENTER để vào chế độ DM và nghe sự kiện KEYCODE_BACK để thoát khỏi chế độ DM, gọi DirectManipulationHelper.enableDirectManipulationMode() trong từng trường hợp. Để lắng nghe những sự kiện này, hãy thực hiện một trong các thao tác sau:
    • Đăng ký OnKeyListener .
    • hoặc,
    • Mở rộng chế độ xem và sau đó ghi đè phương thức dispatchKeyEvent() của nó.
  2. NÊN lắng nghe các sự kiện chuyển động ( KEYCODE_DPAD_UP , KEYCODE_DPAD_DOWN , KEYCODE_DPAD_LEFT hoặc KEYCODE_DPAD_RIGHT ) nếu chế độ xem cần xử lý các chuyển động.
  3. NÊN nghe MotionEvent s và nhận số vòng quay trong AXIS_SCROLL nếu chế độ xem muốn xử lý xoay vòng. Có nhiều hướng khác nhau để làm điều đó:
    1. Đăng ký OnGenericMotionListener .
    2. Mở rộng chế độ xem và ghi đè phương thức dispatchTouchEvent() của nó.
  4. Để tránh bị kẹt ở chế độ DM, PHẢI thoát khỏi chế độ DM khi Phân đoạn hoặc Hoạt động mà chế độ xem thuộc về không tương tác.
  5. NÊN cung cấp tín hiệu trực quan để cho biết rằng chế độ xem đang ở chế độ DM.

Mẫu chế độ xem tùy chỉnh sử dụng chế độ DM để xoay và thu phóng bản đồ được cung cấp bên dưới:

/** 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(); }

Bạn có thể tìm thấy nhiều ví dụ khác trong dự án RotaryPlayground .

Chế độ xem hoạt động

Khi sử dụng Chế độ xem hoạt động:

  • ActivityView không thể lấy nét được.
  • ( Android 11 QPR3, Android 11 Car, không dùng nữa trong Android 11 )
    Nội dung của Chế ActivityView PHẢI chứa FocusParkingView làm chế độ xem có thể lấy tiêu điểm đầu tiên và thuộc tính app:shouldRestoreFocus của nó PHẢI là false .
  • Nội dung của ActivityView không được có chế độ xem android:focusByDefault .

Đối với người dùng, Chế độ xem hoạt động sẽ không ảnh hưởng đến việc điều hướng ngoại trừ các khu vực trọng tâm không thể mở rộng Chế độ xem hoạt động. Nói cách khác, bạn không thể có một khu vực tập trung duy nhất có nội dung bên trong bên ngoài ActivityView . Nếu bạn không thêm bất kỳ FocusAreas nào vào ActivityView của mình thì phần gốc của hệ thống phân cấp chế độ xem trong ActivityView sẽ được coi là khu vực tiêu điểm tiềm ẩn.

Các nút hoạt động khi nhấn giữ

Hầu hết các nút đều gây ra một số hành động khi được nhấp vào. Thay vào đó, một số nút hoạt động khi được nhấn giữ. Ví dụ: các nút Chuyển tiếp nhanh và Tua lại thường hoạt động khi được nhấn giữ. Để làm cho các nút như vậy hỗ trợ quay, hãy lắng nghe KEYCODE_DPAD_CENTER KeyEvents như sau:

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;
});

Trong đó mRunnable thực hiện một hành động (chẳng hạn như tua lại) và tự lên lịch để chạy sau một khoảng thời gian trì hoãn.

Chế độ cảm ứng

Người dùng có thể sử dụng bộ điều khiển quay để tương tác với bộ phận đầu trong ô tô theo hai cách, bằng cách sử dụng bộ điều khiển quay hoặc bằng cách chạm vào màn hình. Khi sử dụng bộ điều khiển quay, một trong các chế độ xem có thể lấy tiêu điểm sẽ được tô sáng. Khi chạm vào màn hình, điểm nhấn tiêu điểm không xuất hiện. Người dùng có thể chuyển đổi giữa các chế độ nhập này bất kỳ lúc nào:

  • Xoay → chạm. Khi người dùng chạm vào màn hình, điểm sáng tiêu điểm sẽ biến mất.
  • Chạm vào → xoay. Khi người dùng di chuyển, xoay hoặc nhấn nút Giữa, điểm đánh dấu tiêu điểm sẽ xuất hiện.

Các nút Quay lại và Trang chủ không có tác dụng đối với chế độ nhập liệu.

Xoay quanh khái niệm chế độ cảm ứng hiện có của Android. Bạn có thể sử dụng View.isInTouchMode() để xác định chế độ nhập mà người dùng đang sử dụng. Bạn có thể sử dụng OnTouchModeChangeListener để lắng nghe các thay đổi. Mặc dù điều này có thể được sử dụng để tùy chỉnh giao diện người dùng của bạn cho chế độ nhập hiện tại, nhưng hãy tránh mọi thay đổi lớn vì chúng có thể gây bối rối.

Xử lý sự cố

Trong ứng dụng được thiết kế cho cảm ứng, thông thường có các chế độ xem có thể lấy tiêu điểm lồng nhau. Ví dụ: có thể có FrameLayout xung quanh ImageButton , cả hai đều có thể lấy tiêu điểm. Điều này không gây hại cho cảm ứng nhưng có thể dẫn đến trải nghiệm người dùng kém khi quay vì người dùng phải xoay bộ điều khiển hai lần để chuyển sang chế độ xem tương tác tiếp theo. Để có trải nghiệm tốt cho người dùng, Google khuyên bạn nên đặt tiêu điểm cho chế độ xem bên ngoài hoặc chế độ xem bên trong chứ không phải cả hai.

Nếu một nút hoặc công tắc mất tiêu điểm khi nhấn qua bộ điều khiển quay, một trong các điều kiện sau có thể áp dụng:

  • Nút hoặc công tắc đang bị vô hiệu hóa (trong thời gian ngắn hoặc vô thời hạn) do nút được nhấn. Trong cả hai trường hợp, có hai cách để giải quyết vấn đề này:
    • Để trạng thái android:enabledtrue và sử dụng trạng thái tùy chỉnh để chuyển nút hoặc chuyển đổi sang màu xám như được mô tả trong Trạng thái tùy chỉnh .
    • Sử dụng vùng chứa để bao quanh nút hoặc công tắc và làm cho vùng chứa có thể lấy tiêu điểm thay vì nút hoặc công tắc. (Trình nghe nhấp chuột phải ở trên vùng chứa.)
  • Nút hoặc công tắc đang được thay thế. Ví dụ: hành động được thực hiện khi nhấn nút hoặc bật công tắc có thể kích hoạt làm mới các hành động sẵn có khiến các nút mới thay thế các nút hiện có. Có hai cách để giải quyết vấn đề này:
    • Thay vì tạo nút hoặc công tắc mới, hãy đặt biểu tượng và/hoặc văn bản của nút hoặc công tắc hiện có.
    • Như trên, thêm vùng chứa có thể lấy tiêu điểm xung quanh nút hoặc công tắc.

quaySân chơi

RotaryPlayground là một ứng dụng tham khảo cho quay. Sử dụng nó để tìm hiểu cách tích hợp các tính năng quay vào ứng dụng của bạn. RotaryPlayground được bao gồm trong các bản dựng trình mô phỏng và trong các bản dựng dành cho thiết bị chạy Android Automotive OS (AAOS).

  • Kho lưu trữ RotaryPlayground : packages/apps/Car/tests/RotaryPlayground/
  • Phiên bản: Android 11 QPR3, Android 11 Car và Android 12

Ứng dụng RotaryPlayground hiển thị các tab sau ở bên trái:

  • Thẻ. Kiểm tra việc điều hướng xung quanh các khu vực trọng tâm, bỏ qua các phần tử không thể lấy nét và nhập văn bản.
  • Thao tác trực tiếp. Kiểm tra các widget hỗ trợ chế độ thao tác trực tiếp đơn giản và nâng cao. Tab này dành riêng cho thao tác trực tiếp trong cửa sổ ứng dụng.
  • Thao tác giao diện người dùng Sys. Kiểm tra các tiện ích hỗ trợ thao tác trực tiếp trong cửa sổ hệ thống chỉ hỗ trợ chế độ thao tác trực tiếp đơn giản.
  • Lưới. Kiểm tra điều hướng xoay kiểu z bằng cách cuộn.
  • Thông báo. Kiểm tra việc đưa vào và ra khỏi thông báo cảnh báo.
  • Cuộn. Kiểm tra việc cuộn qua sự kết hợp giữa nội dung có thể tập trung và không thể tập trung.
  • WebView. Kiểm tra việc điều hướng qua các liên kết trong WebView .
  • FocusArea tùy chỉnh Kiểm tra tùy chỉnh FocusArea :
    • Quấn quanh.
    • android:focusedByDefaultapp:defaultFocus
    • .
    • Mục tiêu thúc đẩy rõ ràng.
    • Di chuyển các phím tắt.
    • FocusArea không có chế độ xem có thể lấy nét.