Kembangkan aplikasi

Materi berikut ditujukan untuk pengembang aplikasi.

Untuk membuat aplikasi Anda mendukung rotasi, Anda HARUS:

  1. Tempatkan FocusParkingView di tata letak aktivitas masing-masing.
  2. Pastikan tampilan yang (atau tidak) dapat difokuskan.
  3. Gunakan FocusArea untuk merangkum semua tampilan fokus Anda, kecuali FocusParkingView .

Masing-masing tugas ini dirinci di bawah, setelah Anda menyiapkan lingkungan untuk mengembangkan aplikasi yang mendukung rotasi.

Siapkan pengontrol putar

Sebelum Anda dapat mulai mengembangkan aplikasi yang mendukung rotasi, Anda memerlukan pengontrol putar atau pengganti. Anda memiliki opsi yang dijelaskan di bawah ini.

Emulator

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

Anda juga dapat menggunakan aosp_car_x86_64-userdebug .

Untuk mengakses pengontrol putar yang ditiru:

  1. Ketuk tiga titik di bagian bawah bilah alat:

    Akses pengontrol putar yang ditiru
    Gambar 1. Akses pengontrol putar yang ditiru
  2. Pilih Putar mobil di jendela kontrol yang diperluas:

    Pilih Putar mobil
    Gambar 2. Pilih Mobil putar

papan ketik USB

  • Colokkan keyboard USB ke perangkat Anda yang menjalankan Android Automotive OS (AAOS). Dalam beberapa kasus, hal ini mencegah munculnya keyboard di layar.
  • Gunakan userdebug atau eng build.
  • Aktifkan pemfilteran peristiwa utama:
    adb shell settings put secure android.car.ROTARY_KEY_EVENT_FILTER 1
    
  • Lihat tabel di bawah untuk menemukan kunci yang sesuai untuk setiap tindakan:
    Kunci Aksi putar
    Q Putar berlawanan arah jarum jam
    E Putar searah jarum jam
    A Dorongan ke kiri
    D Dorongan ke kanan
    W Dorongan ke atas
    S Dorong ke bawah
    F atau Koma Tombol tengah
    R atau Esc Tombol kembali

perintah ADB

Anda dapat menggunakan perintah car_service untuk memasukkan peristiwa masukan putar. Perintah ini dapat dijalankan di perangkat yang menjalankan Android Automotive OS (AAOS) atau di emulator.

perintah car_service Masukan putar
adb shell cmd car_service inject-rotary Putar berlawanan arah jarum jam
adb shell cmd car_service inject-rotary -c true Putar searah jarum jam
adb shell cmd car_service inject-rotary -dt 100 50 Putar berlawanan arah jarum jam beberapa kali (100 mdtk lalu dan 50 mdtk lalu)
adb shell cmd car_service inject-key 282 Dorongan ke kiri
adb shell cmd car_service inject-key 283 Dorongan ke kanan
adb shell cmd car_service inject-key 280 Dorongan ke atas
adb shell cmd car_service inject-key 281 Dorong ke bawah
adb shell cmd car_service inject-key 23 Klik tombol tengah
adb shell input keyevent inject-key 4 Klik tombol kembali

Pengontrol putar OEM

Saat perangkat keras pengontrol putar Anda aktif dan berjalan, ini adalah opsi paling realistis. Ini sangat berguna untuk menguji rotasi cepat.

Tampilan Parkir Fokus

FocusParkingView adalah tampilan transparan di Perpustakaan UI Mobil (car-ui-library) . RotaryService menggunakannya untuk mendukung navigasi pengontrol putar. FocusParkingView harus menjadi tampilan pertama yang dapat difokuskan dalam tata letak. Itu harus ditempatkan di luar semua FocusArea s. Setiap jendela harus memiliki satu FocusParkingView . Jika Anda sudah menggunakan tata letak dasar car-ui-library, yang berisi FocusParkingView , Anda tidak perlu menambahkan FocusParkingView lainnya. Di bawah ini adalah contoh FocusParkingView di 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>

Berikut adalah alasan Anda memerlukan FocusParkingView :

  1. Android tidak menghapus fokus secara otomatis ketika fokus diatur di jendela lain. Jika Anda mencoba menghapus fokus di jendela sebelumnya, Android akan memfokuskan kembali tampilan di jendela tersebut, sehingga menghasilkan dua jendela yang difokuskan secara bersamaan. Menambahkan FocusParkingView ke setiap jendela dapat memperbaiki masalah ini. Tampilan ini transparan dan sorotan fokus defaultnya dinonaktifkan, sehingga tidak terlihat oleh pengguna, baik terfokus atau tidak. Diperlukan fokus agar RotaryService dapat memarkir fokus padanya untuk menghilangkan sorotan fokus.
  2. Jika hanya ada satu FocusArea di jendela saat ini, memutar pengontrol di FocusArea menyebabkan RotaryService memindahkan fokus dari tampilan di sebelah kanan ke tampilan di sebelah kiri (dan sebaliknya). Menambahkan tampilan ini ke setiap jendela dapat memperbaiki masalah ini. Ketika RotaryService menentukan target fokus adalah FocusParkingView , RotaryService dapat menentukan penyelesaian akan segera terjadi dan pada titik mana ia menghindari penyelesaian dengan tidak memindahkan fokus.
  3. Saat kontrol putar meluncurkan aplikasi, Android memfokuskan tampilan fokus pertama, yang selalu berupa FocusParkingView . FocusParkingView menentukan tampilan optimal untuk difokuskan dan kemudian menerapkan fokus.

Pandangan yang dapat difokuskan

RotaryService dibangun berdasarkan konsep fokus tampilan kerangka Android yang sudah ada , sejak ponsel memiliki keyboard fisik dan D-pad. Atribut android:nextFocusForward yang ada digunakan ulang untuk rotasi (lihat penyesuaian FocusArea ), namun android:nextFocusLeft , android:nextFocusRight , android:nextFocusUp , dan android:nextFocusDown tidak.

RotaryService hanya berfokus pada pandangan yang dapat difokuskan. Beberapa tampilan, misalnya Button , biasanya dapat difokuskan. Lainnya, seperti TextView s dan ViewGroup s, biasanya tidak. Tampilan yang dapat diklik secara otomatis dapat difokus dan tampilan secara otomatis dapat diklik ketika memiliki pemroses klik. Jika logika otomatis ini menghasilkan fokus yang diinginkan, Anda tidak perlu mengatur fokus tampilan secara eksplisit. Jika logika otomatis tidak menghasilkan kemampuan fokus yang diinginkan, setel atribut android:focusable ke true atau false , atau setel fokusabilitas tampilan secara terprogram dengan View.setFocusable(boolean) . Agar RotaryService dapat fokus pada hal tersebut, suatu tampilan HARUS memenuhi persyaratan berikut:

  • Dapat difokuskan
  • Diaktifkan
  • Bisa dilihat
  • Memiliki nilai bukan nol untuk lebar dan tinggi

Jika tampilan tidak memenuhi semua persyaratan ini, misalnya tombol dapat difokus namun dinonaktifkan, pengguna tidak dapat menggunakan kontrol putar untuk memfokuskannya. Jika Anda ingin fokus pada tampilan yang dinonaktifkan, pertimbangkan untuk menggunakan status khusus, bukan android:state_enabled untuk mengontrol tampilan tampilan tanpa menunjukkan bahwa Android harus menganggapnya dinonaktifkan. Aplikasi Anda dapat memberi tahu pengguna mengapa tampilan dinonaktifkan saat diketuk. Bagian selanjutnya menjelaskan cara melakukan ini.

Negara bagian khusus

Untuk menambahkan status khusus:

  1. Untuk menambahkan atribut khusus ke tampilan Anda. Misalnya, untuk menambahkan status kustom state_rotary_enabled ke kelas tampilan CustomView , gunakan:
    <declare-styleable name="CustomView">
        <attr name="state_rotary_enabled" format="boolean" />
    </declare-styleable>
    
  2. Untuk melacak keadaan ini, tambahkan variabel instan ke tampilan Anda bersama dengan metode pengakses:
    private boolean mRotaryEnabled;
    public boolean getRotaryEnabled() { return mRotaryEnabled; }
    public void setRotaryEnabled(boolean rotaryEnabled) {
        mRotaryEnabled = rotaryEnabled;
    }
    
  3. Untuk membaca nilai atribut Anda saat tampilan Anda dibuat:
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView);
    mRotaryEnabled = a.getBoolean(R.styleable.CustomView_state_rotary_enabled);
    
  4. Di kelas tampilan Anda, ganti metode onCreateDrawableState() lalu tambahkan status kustom, jika diperlukan. Misalnya:
    @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. Jadikan pengendali klik tampilan Anda bekerja secara berbeda bergantung pada statusnya. Misalnya, pengendali klik mungkin tidak melakukan apa pun atau mungkin muncul bersulang ketika mRotaryEnabled bernilai false .
  6. Untuk membuat tombol tampak dinonaktifkan, di latar belakang tampilan Anda yang dapat digambar, gunakan app:state_rotary_enabled alih-alih android:state_enabled . Jika Anda belum memilikinya, Anda perlu menambahkan:
    xmlns:app="http://schemas.android.com/apk/res-auto"
    
  7. Jika tampilan Anda dinonaktifkan di tata letak apa pun, ganti android:enabled="false" dengan app:state_rotary_enabled="false" lalu tambahkan namespace app , seperti di atas.
  8. Jika tampilan Anda dinonaktifkan secara terprogram, ganti panggilan ke setEnabled() dengan panggilan ke setRotaryEnabled() .

Area fokus

Gunakan FocusAreas untuk mempartisi tampilan yang dapat difokuskan menjadi beberapa blok agar navigasi lebih mudah dan konsisten dengan aplikasi lain. Misalnya, jika aplikasi Anda memiliki toolbar, toolbar tersebut harus berada di FocusArea terpisah dari aplikasi Anda lainnya. Bilah tab dan elemen navigasi lainnya juga harus dipisahkan dari aplikasi lainnya. Daftar besar umumnya harus memiliki FocusArea sendiri. Jika tidak, pengguna harus memutar seluruh daftar untuk mengakses beberapa tampilan.

FocusArea adalah subkelas LinearLayout di perpustakaan car-ui. Saat fitur ini diaktifkan, FocusArea akan menyorot saat salah satu turunannya terfokus. Untuk mempelajari lebih lanjut, lihat Kustomisasi sorotan fokus .

Saat membuat blok navigasi di file tata letak, jika Anda ingin menggunakan LinearLayout sebagai kontainer untuk blok tersebut, gunakan FocusArea sebagai gantinya. Jika tidak, bungkus blok dalam FocusArea .

JANGAN menumpuk FocusArea di FocusArea lain. Melakukan hal ini akan menyebabkan perilaku navigasi yang tidak terdefinisi. Pastikan semua tampilan yang dapat difokus berada di dalam FocusArea .

Contoh FocusArea di RotaryPlayground ditunjukkan di bawah ini:

<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 berfungsi sebagai berikut:

  1. Saat menangani tindakan memutar dan menyenggol, RotaryService mencari contoh FocusArea dalam hierarki tampilan.
  2. Saat menerima peristiwa rotasi, RotaryService memindahkan fokus ke Tampilan lain yang dapat mengambil fokus di FocusArea yang sama.
  3. Saat menerima peristiwa dorongan, RotaryService memindahkan fokus ke tampilan lain yang dapat mengambil fokus di FocusArea lain (biasanya berdekatan).

Jika Anda tidak menyertakan FocusAreas apa pun dalam tata letak Anda, tampilan akar akan diperlakukan sebagai area fokus implisit. Pengguna tidak dapat mendorong untuk bernavigasi di aplikasi. Sebaliknya, mereka akan memutar seluruh tampilan yang dapat difokuskan, yang mungkin cukup untuk dialog.

Kustomisasi Area Fokus

Dua atribut Tampilan standar dapat digunakan untuk menyesuaikan navigasi putar:

  • android:nextFocusForward memungkinkan pengembang aplikasi menentukan urutan rotasi di area fokus. Ini adalah atribut yang sama yang digunakan untuk mengontrol urutan Tab untuk navigasi keyboard. JANGAN gunakan atribut ini untuk membuat loop. Sebagai gantinya, gunakan app:wrapAround (lihat di bawah) untuk membuat loop.
  • android:focusedByDefault memungkinkan pengembang aplikasi menentukan tampilan fokus default di jendela. JANGAN gunakan atribut dan app:defaultFocus ini (lihat di bawah) di FocusArea yang sama.

FocusArea juga menentukan beberapa atribut untuk menyesuaikan navigasi putar. Area fokus implisit tidak dapat disesuaikan dengan atribut ini.

  1. ( Android 11 QPR3, Android 11 Mobil, Android 12 )
    app:defaultFocus dapat digunakan untuk menentukan ID tampilan turunan yang dapat difokus, yang harus difokuskan ketika pengguna mengarahkan ke FocusArea ini.
  2. ( Android 11 QPR3, Android 11 Mobil, Android 12 )
    app:defaultFocusOverridesHistory dapat disetel ke true untuk membuat tampilan yang ditentukan di atas mengambil fokus meskipun dengan riwayat untuk menunjukkan tampilan lain di FocusArea ini telah difokuskan.
  3. ( Android 12 )
    Gunakan app:nudgeLeftShortcut , app:nudgeRightShortcut , app:nudgeUpShortcut , dan app:nudgeDownShortcut untuk menentukan ID tampilan turunan yang dapat difokuskan, yang harus difokuskan saat pengguna mendorong ke arah tertentu. Untuk mempelajari lebih lanjut, lihat konten pintasan nudge di bawah.

    ( Android 11 QPR3, Android 11 Car, tidak digunakan lagi di Android 12 ) app:nudgeShortcut dan app:nudgeShortcutDirection hanya mendukung satu pintasan nudge.

  4. ( Android 11 QPR3, Android 11 Mobil, Android 12 )
    Untuk mengaktifkan rotasi di FocusArea ini, app:wrapAround dapat disetel ke true . Ini paling sering digunakan ketika tampilan disusun dalam lingkaran atau oval.
  5. ( Android 11 QPR3, Android 11 Mobil, Android 12 )
    Untuk menyesuaikan padding sorotan di FocusArea ini, gunakan app:highlightPaddingStart , app:highlightPaddingEnd , app:highlightPaddingTop , app:highlightPaddingBottom , app:highlightPaddingHorizontal , dan app:highlightPaddingVertical .
  6. ( Android 11 QPR3, Android 11 Mobil, Android 12 )
    Untuk menyesuaikan batas yang dirasakan FocusArea ini guna menemukan target dorongan, gunakan app:startBoundOffset , app:endBoundOffset , app:topBoundOffset , app:bottomBoundOffset , app:horizontalBoundOffset , dan app:verticalBoundOffset .
  7. ( Android 11 QPR3, Android 11 Mobil, Android 12 )
    Untuk secara eksplisit menentukan ID FocusArea (atau area) yang berdekatan dalam arah tertentu, gunakan app:nudgeLeft , app:nudgeRight , app:nudgeUp , dan app:nudgeDown . Gunakan ini ketika pencarian geometris yang digunakan secara default tidak menemukan target yang diinginkan.

Menyenggol biasanya menavigasi di antara Area Fokus. Namun dengan pintasan dorongan, terkadang dorongan akan menavigasi terlebih dahulu dalam FocusArea sehingga pengguna mungkin perlu mendorong dua kali untuk menavigasi ke FocusArea berikutnya. Pintasan dorongan berguna ketika FocusArea berisi daftar panjang diikuti dengan Tombol Tindakan Mengambang , seperti pada contoh di bawah ini:

Pintasan dorongan
Gambar 3. Pintasan dorongan

Tanpa pintasan dorongan, pengguna harus memutar seluruh daftar untuk mencapai FAB.

Kustomisasi sorotan fokus

Seperti disebutkan di atas, RotaryService dibangun berdasarkan konsep fokus tampilan kerangka Android yang sudah ada. Saat pengguna memutar dan mendorong, RotaryService memindahkan fokus, memfokuskan satu tampilan dan menghilangkan fokus lainnya. Di Android, saat tampilan terfokus, jika tampilan:

  • Telah menentukan sorotan fokusnya sendiri, Android menggambar sorotan fokus tampilan.
  • Tidak menentukan sorotan fokus, dan sorotan fokus default tidak dinonaktifkan, Android menggambar sorotan fokus default untuk tampilan.

Aplikasi yang dirancang untuk sentuhan biasanya tidak menentukan sorotan fokus yang sesuai.

Sorotan fokus default disediakan oleh kerangka kerja Android dan dapat diganti oleh OEM. Pengembang aplikasi menerimanya ketika tema yang mereka gunakan berasal dari Theme.DeviceDefault .

Untuk pengalaman pengguna yang konsisten, andalkan sorotan fokus default bila memungkinkan. Jika Anda memerlukan sorotan fokus berbentuk khusus (misalnya, bulat atau berbentuk pil), atau jika Anda menggunakan tema yang bukan berasal dari Theme.DeviceDefault , gunakan sumber daya car-ui-library untuk menentukan sorotan fokus Anda sendiri untuk setiap tampilan.

Untuk menentukan sorotan fokus kustom pada suatu tampilan, ubah latar belakang atau latar depan tampilan menjadi sumber daya dapat digambar yang berbeda saat tampilan difokuskan. Biasanya, Anda akan mengubah latar belakang. Sumber daya dapat digambar berikut, jika digunakan sebagai latar belakang untuk tampilan persegi, akan menghasilkan sorotan fokus bulat:

<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 ) Referensi resource yang dicetak tebal pada contoh di atas mengidentifikasi resource yang ditentukan oleh car-ui-library. OEM mengesampingkannya agar konsisten dengan sorotan fokus default yang mereka tentukan. Hal ini memastikan bahwa warna sorotan fokus, lebar guratan, dan sebagainya tidak berubah saat pengguna menavigasi antara tampilan dengan sorotan fokus kustom dan tampilan dengan sorotan fokus default. Item terakhir adalah riak yang digunakan untuk sentuhan. Nilai default yang digunakan untuk sumber daya yang dicetak tebal muncul sebagai berikut:

Nilai default untuk sumber daya yang berani
Gambar 4. Nilai default untuk sumber daya yang dicetak tebal

Selain itu, sorotan fokus khusus dipanggil ketika tombol diberi warna latar belakang solid untuk menarik perhatian pengguna, seperti pada contoh di bawah. Hal ini dapat membuat sorotan fokus sulit dilihat. Dalam situasi ini, tentukan sorotan fokus khusus menggunakan warna sekunder :

Warna latar belakang solid
  • ( Android 11 QPR3, Android 11 Mobil, 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

Misalnya:

Fokus, bukan ditekanFokus, ditekan
Fokus, bukan ditekan Fokus, ditekan

Pengguliran putar

Jika aplikasi Anda menggunakan RecyclerView s, Anda HARUS menggunakan CarUiRecyclerView s sebagai gantinya. Hal ini memastikan bahwa UI Anda konsisten dengan yang lain karena penyesuaian OEM berlaku untuk semua CarUiRecyclerView s.

Jika semua elemen dalam daftar Anda dapat difokuskan, Anda tidak perlu melakukan hal lain. Navigasi putar memindahkan fokus melalui elemen dalam daftar dan daftar bergulir untuk membuat elemen fokus baru terlihat.

( Android 11 QPR3, Android 11 Mobil, Android 12 )
Jika terdapat campuran elemen yang dapat difokuskan dan tidak dapat difokuskan, atau jika semua elemen tidak dapat fokus, Anda dapat mengaktifkan pengguliran putar, yang memungkinkan pengguna menggunakan pengontrol putar untuk menggulir daftar secara bertahap tanpa melewatkan item yang tidak dapat fokus. Untuk mengaktifkan pengguliran putar, setel atribut app:rotaryScrollEnabled ke true .

( Android 11 QPR3, Android 11 Mobil, Android 12 )
Anda dapat mengaktifkan pengguliran putar dalam tampilan apa pun yang dapat digulir, termasuk CarUiRecyclerView , dengan metode setRotaryScrollEnabled() di CarUiUtils . Jika Anda melakukannya, Anda perlu:

  • Menjadikan tampilan yang dapat digulir dapat difokuskan sehingga dapat difokuskan ketika tidak ada tampilan turunan yang dapat difokus yang terlihat,
  • Nonaktifkan sorotan fokus default pada tampilan yang dapat digulir dengan memanggil setDefaultFocusHighlightEnabled(false) sehingga tampilan yang dapat digulir tidak tampak fokus,
  • Pastikan tampilan yang dapat digulir difokuskan sebelum turunannya dengan memanggil setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS) .
  • Dengarkan MotionEvents dengan SOURCE_ROTARY_ENCODER dan AXIS_VSCROLL atau AXIS_HSCROLL untuk menunjukkan jarak untuk menggulir dan arah (melalui tanda).

Saat pengguliran putar diaktifkan pada CarUiRecyclerView dan pengguna memutar ke area di mana tidak ada tampilan yang dapat difokuskan, bilah gulir akan berubah dari abu-abu menjadi biru, seolah-olah menunjukkan bahwa bilah gulir sedang difokuskan. Anda dapat menerapkan efek serupa jika Anda mau.

MotionEvents sama dengan yang dihasilkan oleh roda gulir pada mouse, kecuali sumbernya.

Mode manipulasi langsung

Biasanya, dorongan dan rotasi menavigasi antarmuka pengguna, sementara penekanan tombol Tengah akan mengambil tindakan, meskipun hal ini tidak selalu terjadi. Misalnya, jika pengguna ingin menyesuaikan volume alarm, mereka mungkin menggunakan pengontrol putar untuk menavigasi ke penggeser volume, tekan tombol Tengah, putar pengontrol untuk menyesuaikan volume alarm, lalu tekan tombol Kembali untuk kembali ke navigasi . Ini disebut sebagai mode manipulasi langsung (DM) . Dalam mode ini, pengontrol putar digunakan untuk berinteraksi dengan tampilan secara langsung, bukan untuk bernavigasi.

Terapkan DM dengan salah satu dari dua cara. Jika Anda hanya perlu menangani rotasi dan tampilan yang ingin Anda manipulasi merespons ACTION_SCROLL_FORWARD dan ACTION_SCROLL_BACKWARD AccessibilityEvent dengan tepat, gunakan mekanisme sederhana . Jika tidak, gunakan mekanisme lanjutan .

Mekanisme sederhana adalah satu-satunya pilihan di sistem windows; aplikasi dapat menggunakan salah satu mekanisme tersebut.

Mekanisme sederhana

( Android 11 QPR3, Android 11 Mobil, Android 12 )
Aplikasi Anda harus memanggil DirectManipulationHelper.setSupportsRotateDirectly(View view, boolean enable) . RotaryService mengenali saat pengguna berada dalam mode DM dan memasuki mode DM saat pengguna menekan tombol Tengah saat tampilan terfokus. Saat dalam mode DM, rotasi dilakukan ACTION_SCROLL_FORWARD atau ACTION_SCROLL_BACKWARD dan keluar dari mode DM ketika pengguna menekan tombol Kembali. Mekanisme sederhananya mengubah status tampilan yang dipilih saat masuk dan keluar dari mode DM.

Untuk memberikan isyarat visual bahwa pengguna sedang dalam mode DM, buat tampilan Anda tampil berbeda saat dipilih. Misalnya, ubah latar belakang jika android:state_selected bernilai true .

Mekanisme tingkat lanjut

Aplikasi ini menentukan kapan RotaryService masuk dan keluar dari mode DM. Untuk pengalaman pengguna yang konsisten, menekan tombol Tengah dengan tampilan DM terfokus akan masuk ke mode DM dan tombol Kembali harus keluar dari mode DM. Jika tombol Tengah dan/atau dorongan tidak digunakan, itu bisa menjadi cara alternatif untuk keluar dari mode DM. Untuk aplikasi seperti Maps, tombol untuk mewakili DM dapat digunakan untuk masuk ke mode DM.

Untuk mendukung mode DM tingkat lanjut, tampilan:

  1. ( Android 11 QPR3, Android 11 Mobil, Android 12 ) HARUS mendengarkan peristiwa KEYCODE_DPAD_CENTER untuk masuk ke mode DM dan mendengarkan peristiwa KEYCODE_BACK untuk keluar dari mode DM, dengan memanggil DirectManipulationHelper.enableDirectManipulationMode() dalam setiap kasus. Untuk mendengarkan peristiwa ini, lakukan salah satu hal berikut:
    • Daftarkan OnKeyListener .
    • atau,
    • Perluas tampilan lalu ganti metode dispatchKeyEvent() -nya.
  2. HARUS mendengarkan peristiwa nudge ( KEYCODE_DPAD_UP , KEYCODE_DPAD_DOWN , KEYCODE_DPAD_LEFT , atau KEYCODE_DPAD_RIGHT ) jika tampilan harus menangani nudge.
  3. HARUS mendengarkan MotionEvent dan mendapatkan jumlah rotasi di AXIS_SCROLL jika tampilan ingin menangani rotasi. Ada beberapa cara untuk melakukan ini:
    1. Daftarkan OnGenericMotionListener .
    2. Perluas tampilan dan ganti metode dispatchTouchEvent() -nya.
  4. Untuk menghindari terjebak dalam mode DM, HARUS keluar dari mode DM ketika Fragmen atau Aktivitas yang dimiliki tampilan tidak interaktif.
  5. HARUS memberikan isyarat visual untuk menunjukkan bahwa tampilan berada dalam mode DM.

Contoh tampilan kustom yang menggunakan mode DM untuk menggeser dan memperbesar peta disediakan di bawah:

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

Contoh lainnya dapat ditemukan di proyek RotaryPlayground .

Tampilan Aktivitas

Saat menggunakan ActivityView:

  • ActivityView tidak boleh fokus.
  • ( Android 11 QPR3, Android 11 Mobil, tidak digunakan lagi di Android 11 )
    Konten ActivityView HARUS berisi FocusParkingView sebagai tampilan fokus pertama, dan atribut app:shouldRestoreFocus -nya HARUS false .
  • Konten ActivityView tidak boleh memiliki tampilan android:focusByDefault .

Bagi pengguna, ActivityViews seharusnya tidak berpengaruh pada navigasi kecuali area fokus tidak dapat menjangkau ActivityViews. Dengan kata lain, Anda tidak bisa memiliki satu area fokus yang memiliki konten di dalam dan di luar ActivityView . Jika Anda tidak menambahkan FocusArea apa pun ke ActivityView Anda, akar hierarki tampilan di ActivityView dianggap sebagai area fokus implisit.

Tombol yang beroperasi saat ditekan

Kebanyakan tombol menyebabkan beberapa tindakan saat diklik. Beberapa tombol beroperasi ketika ditekan. Misalnya, tombol Fast Forward dan Rewind biasanya beroperasi saat ditekan. Untuk membuat tombol tersebut mendukung putaran, dengarkan KEYCODE_DPAD_CENTER KeyEvents sebagai berikut:

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

Di mana mRunnable mengambil tindakan (seperti memutar ulang) dan menjadwalkan dirinya untuk dijalankan setelah penundaan.

Modus sentuh

Pengguna dapat menggunakan pengontrol putar untuk berinteraksi dengan head unit di dalam mobil dengan dua cara, baik menggunakan pengontrol putar atau dengan menyentuh layar. Saat menggunakan pengontrol putar, salah satu tampilan yang dapat difokuskan disorot. Saat menyentuh layar, tidak ada sorotan fokus yang muncul. Pengguna dapat beralih di antara mode masukan ini kapan saja:

  • Putar → sentuh. Saat pengguna menyentuh layar, sorotan fokus menghilang.
  • Sentuh → putar. Saat pengguna menyenggol, memutar, atau menekan tombol Tengah, sorotan fokus muncul.

Tombol Kembali dan Beranda tidak berpengaruh pada mode input.

Dukungan putar pada konsep mode sentuh yang ada di Android. Anda dapat menggunakan View.isInTouchMode() untuk menentukan mode input mana yang digunakan pengguna. Anda dapat menggunakan OnTouchModeChangeListener untuk mendengarkan perubahan. Meskipun ini dapat digunakan untuk menyesuaikan antarmuka pengguna Anda untuk mode masukan saat ini, hindari perubahan besar apa pun karena dapat membingungkan.

Penyelesaian masalah

Dalam aplikasi yang didesain untuk sentuhan, biasanya terdapat tampilan terfokus yang bertumpuk. Misalnya, mungkin ada FrameLayout di sekitar ImageButton , keduanya dapat difokus. Hal ini tidak membahayakan sentuhan tetapi dapat mengakibatkan pengalaman pengguna yang buruk untuk memutar karena pengguna harus memutar pengontrol dua kali untuk berpindah ke tampilan interaktif berikutnya. Untuk pengalaman pengguna yang baik, Google menyarankan Anda membuat tampilan luar atau tampilan dalam dapat fokus, namun tidak keduanya.

Jika tombol atau sakelar kehilangan fokus saat ditekan melalui pengontrol putar, salah satu kondisi berikut mungkin berlaku:

  • Tombol atau sakelar dinonaktifkan (sebentar atau tanpa batas waktu) karena tombol ditekan. Apa pun kasusnya, ada dua cara untuk mengatasi hal ini:
    • Biarkan status android:enabled sebagai true dan gunakan status kustom untuk menghilangkan warna tombol atau tombol seperti yang dijelaskan dalam Custom State .
    • Gunakan wadah untuk mengelilingi tombol atau sakelar dan buat wadah tersebut dapat difokuskan, bukan tombol atau sakelar. (Pemroses klik harus ada di penampung.)
  • Tombol atau sakelar sedang diganti. Misalnya, tindakan yang diambil saat tombol ditekan atau tombol dialihkan mungkin memicu penyegaran tindakan yang tersedia sehingga menyebabkan tombol baru menggantikan tombol yang sudah ada. Ada dua cara untuk mengatasi hal ini:
    • Daripada membuat tombol atau tombol baru, atur ikon dan/atau teks tombol atau tombol yang ada.
    • Seperti di atas, tambahkan wadah yang dapat difokuskan di sekitar tombol atau sakelar.

Taman Bermain Putar

RotaryPlayground adalah aplikasi referensi untuk rotary. Gunakan ini untuk mempelajari cara mengintegrasikan fitur putar ke dalam aplikasi Anda. RotaryPlayground disertakan dalam build emulator dan build untuk perangkat yang menjalankan Android Automotive OS (AAOS).

  • Repositori RotaryPlayground : packages/apps/Car/tests/RotaryPlayground/
  • Versi: Android 11 QPR3, Android 11 Mobil, dan Android 12

Aplikasi RotaryPlayground menampilkan tab berikut di sebelah kiri:

  • Kartu-kartu. Uji navigasi di sekitar area fokus, lewati elemen yang tidak fokus dan input teks.
  • Manipulasi Langsung. Uji widget yang mendukung mode manipulasi langsung sederhana dan lanjutan. Tab ini khusus untuk manipulasi langsung dalam jendela aplikasi.
  • Manipulasi Sistem UI. Uji widget yang mendukung manipulasi langsung di jendela sistem yang hanya mendukung mode manipulasi langsung sederhana.
  • jaringan. Uji navigasi putar pola-z dengan menggulir.
  • Pemberitahuan. Uji dorongan masuk dan keluar dari notifikasi pendahuluan.
  • Menggulir. Uji menelusuri campuran konten yang dapat difokuskan dan tidak dapat difokuskan.
  • Tampilan Web. Uji navigasi melalui tautan di WebView .
  • FocusArea Kustom. Uji kustomisasi FocusArea :
    • Membungkus.
    • android:focusedByDefault dan app:defaultFocus
    • .
    • Target dorongan yang eksplisit.
    • Dorongan jalan pintas.
    • FocusArea tanpa tampilan yang dapat difokuskan.