Materi berikut ditujukan untuk developer aplikasi.
Agar aplikasi mendukung rotary, Anda HARUS:
- Tempatkan
FocusParkingView
di tata letak aktivitas masing-masing. - Pastikan tampilan yang dapat (atau tidak dapat) difokuskan.
- Gunakan
FocusArea
untuk menggabungkan semua tampilan yang dapat difokuskan, kecualiFocusParkingView
.
Setiap tugas ini dijelaskan di bawah, setelah Anda menyiapkan lingkungan untuk mengembangkan aplikasi yang mendukung rotary.
Menyiapkan pengontrol rotasi
Sebelum dapat mulai mengembangkan aplikasi yang mendukung rotary, Anda memerlukan pengontrol rotary atau pengganti. Anda memiliki opsi yang dijelaskan di bawah.
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 diemulasi:
- Ketuk tiga titik di bagian bawah toolbar:
Gambar 1. Mengakses pengontrol rotasi yang diemulasi - Pilih Car rotary di jendela extended controls:
Gambar 2. Pilih Putar mobil
Keyboard USB
- Colokkan keyboard USB ke perangkat Anda yang menjalankan Android Automotive OS (AAOS). Dalam beberapa kasus, hal ini mencegah keyboard virtual muncul.
- Gunakan build
userdebug
ataueng
. - Mengaktifkan 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 Tindakan dari tombol putar T Putar berlawanan arah jarum jam E Putar searah jarum jam A Geser ke Kiri D Geser ke Kanan W Geser ke Atas S Geser ke Bawah F atau Koma Tombol tengah R atau Esc Tombol kembali
Perintah ADB
Anda dapat menggunakan perintah car_service
untuk memasukkan peristiwa input rotasi. Perintah ini
dapat dijalankan di perangkat yang menjalankan Android Automotive OS (AAOS) atau di emulator.
perintah car_service | Input dari alat rotasi |
---|---|
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 |
Memutar berlawanan arah jarum jam beberapa kali (100 md yang lalu dan 50 md yang lalu) |
adb shell cmd car_service inject-key 282 |
Geser ke Kiri |
adb shell cmd car_service inject-key 283 |
Geser ke Kanan |
adb shell cmd car_service inject-key 280 |
Geser ke Atas |
adb shell cmd car_service inject-key 281 |
Geser ke Bawah |
adb shell cmd car_service inject-key 23 |
Klik tombol tengah |
adb shell input keyevent inject-key 4 |
Klik tombol Kembali |
Rotary controller OEM
Saat hardware pengontrol rotari Anda sudah aktif dan berjalan, ini adalah opsi yang paling realistis. Hal ini sangat berguna untuk menguji rotasi cepat.
FocusParkingView
FocusParkingView
adalah tampilan transparan di
Library UI Mobil (car-ui-library).
RotaryService
menggunakannya untuk mendukung navigasi pengontrol rotasi.
FocusParkingView
harus menjadi tampilan pertama yang dapat difokuskan
dalam tata letak. Elemen ini harus ditempatkan di luar semua FocusArea
. Setiap jendela harus memiliki satu
FocusParkingView
. Jika sudah menggunakan tata letak dasar car-ui-library,
yang berisi FocusParkingView
, Anda tidak perlu menambahkan
FocusParkingView
lain. Berikut 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
:
- Android tidak menghapus fokus secara otomatis saat fokus ditetapkan di jendela lain. Jika Anda
mencoba menghapus fokus di jendela sebelumnya, Android akan memfokuskan ulang tampilan di jendela tersebut, yang
mengakibatkan dua jendela difokuskan secara bersamaan. Menambahkan
FocusParkingView
ke setiap jendela dapat memperbaiki masalah ini. Tampilan ini bersifat transparan dan sorotan fokus defaultnya dinonaktifkan, sehingga tidak terlihat oleh pengguna, terlepas dari apakah difokuskan atau tidak. Tindakan ini dapat mengambil fokus sehinggaRotaryService
dapat memarkir fokus di dalamnya untuk menghapus sorotan fokus. - Jika hanya ada satu
FocusArea
di jendela saat ini, memutar pengontrol diFocusArea
akan menyebabkanRotaryService
memindahkan fokus dari tampilan di sebelah kanan ke tampilan di sebelah kiri (dan sebaliknya). Menambahkan tampilan ini ke setiap jendela dapat memperbaiki masalah. SaatRotaryService
menentukan target fokus adalahFocusParkingView
,RotaryService
dapat menentukan bahwa penggabungan akan terjadi, dan pada titik tersebut,RotaryService
akan menghindari penggabungan dengan tidak memindahkan fokus. - Saat kontrol putar meluncurkan aplikasi, Android akan memfokuskan tampilan pertama yang dapat difokuskan,
yang selalu berupa
FocusParkingView
.FocusParkingView
menentukan tampilan optimal yang akan difokuskan, lalu menerapkan fokus.
Tampilan yang dapat difokuskan
RotaryService
dibuat berdasarkan konsep fokus tampilan
yang ada
pada framework Android, yang berasal dari saat ponsel memiliki keyboard fisik dan D-pad.
Atribut android:nextFocusForward
yang ada digunakan kembali untuk perangkat putar
(lihat Penyesuaian FocusArea), tetapi
android:nextFocusLeft
, android:nextFocusRight
,
android:nextFocusUp
, dan android:nextFocusDown
tidak.
RotaryService
hanya berfokus pada tampilan yang dapat difokuskan. Beberapa tampilan,
seperti Button
,
biasanya dapat difokuskan. Yang lainnya, seperti TextView
dan ViewGroup
,
biasanya tidak. Tampilan yang dapat diklik secara otomatis dapat difokuskan dan tampilan secara otomatis
dapat diklik jika memiliki pemroses klik. Jika logika otomatis ini menghasilkan fokus
yang diinginkan, Anda tidak perlu menetapkan fokus tampilan secara eksplisit. Jika logika otomatis tidak
menghasilkan kemampuan fokus yang diinginkan, tetapkan atribut android:focusable
ke
true
atau false
, atau tetapkan kemampuan fokus tampilan secara terprogram dengan
View.setFocusable(boolean)
. Agar RotaryService
berfokus pada tampilan, tampilan HARUS
memenuhi persyaratan berikut:
- Dapat difokuskan
- Aktif
- Terlihat
- Memiliki nilai non-nol untuk lebar dan tinggi
Jika tampilan tidak memenuhi semua persyaratan ini, misalnya tombol yang dapat difokuskan tetapi dinonaktifkan,
pengguna tidak dapat menggunakan kontrol putar untuk berfokus pada tombol tersebut. Jika Anda ingin berfokus pada tampilan yang dinonaktifkan,
pertimbangkan untuk menggunakan status kustom, bukan android:state_enabled
, untuk mengontrol cara
tampilan muncul tanpa menunjukkan bahwa Android harus menganggapnya dinonaktifkan. Aplikasi Anda dapat memberi tahu
pengguna alasan tampilan dinonaktifkan saat diketuk. Bagian berikutnya menjelaskan cara melakukannya.
Status kustom
Untuk menambahkan status kustom:
- Untuk menambahkan atribut kustom
ke tampilan Anda. Misalnya, untuk menambahkan status kustom
state_rotary_enabled
ke class tampilanCustomView
, gunakan:<declare-styleable name="CustomView"> <attr name="state_rotary_enabled" format="boolean" /> </declare-styleable>
- Untuk melacak status ini, tambahkan variabel instance ke tampilan Anda beserta metode pengakses:
private boolean mRotaryEnabled; public boolean getRotaryEnabled() { return mRotaryEnabled; } public void setRotaryEnabled(boolean rotaryEnabled) { mRotaryEnabled = rotaryEnabled; }
- Untuk membaca nilai atribut saat tampilan dibuat:
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView); mRotaryEnabled = a.getBoolean(R.styleable.CustomView_state_rotary_enabled);
- Di class tampilan, ganti metode
onCreateDrawableState()
, lalu tambahkan status kustom, jika sesuai. Contoh:@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; }
- Buat pengendali klik tampilan Anda berperforma berbeda-beda, bergantung pada statusnya. Misalnya, pengendali klik mungkin tidak melakukan apa pun atau mungkin memunculkan toast saat
mRotaryEnabled
adalahfalse
. - Agar tombol tampak dinonaktifkan, di drawable latar belakang tampilan, gunakan
app:state_rotary_enabled
, bukanandroid:state_enabled
. Jika belum memilikinya, Anda harus menambahkan:xmlns:app="http://schemas.android.com/apk/res-auto"
- Jika tampilan Anda dinonaktifkan di tata letak apa pun, ganti
android:enabled="false"
denganapp:state_rotary_enabled="false"
, lalu tambahkan namespaceapp
, seperti di atas. - Jika tampilan Anda dinonaktifkan secara terprogram, ganti panggilan ke
setEnabled()
dengan panggilan kesetRotaryEnabled()
.
FocusArea
Gunakan FocusAreas
untuk mempartisi tampilan yang dapat difokuskan menjadi beberapa blok untuk mempermudah
navigasi dan agar konsisten dengan aplikasi lain. Misalnya, jika aplikasi Anda memiliki toolbar, toolbar
harus berada di FocusArea
terpisah dari aplikasi lainnya. Panel tab dan
elemen navigasi lainnya juga harus dipisahkan dari aplikasi lainnya. Daftar besar
umumnya harus memiliki FocusArea
-nya sendiri. Jika tidak, pengguna harus memutar
seluruh daftar untuk mengakses beberapa tampilan.
FocusArea
adalah subclass dari LinearLayout
di library car-ui.
Jika fitur ini diaktifkan, FocusArea
akan menggambar sorotan saat salah satu
turunan difokuskan. Untuk mempelajari lebih lanjut, lihat
Penyesuaian sorotan fokus.
Saat membuat blok navigasi dalam file tata letak, jika Anda ingin menggunakan
LinearLayout
sebagai penampung untuk blok tersebut, gunakan FocusArea
.
Jika tidak, gabungkan blok dalam FocusArea
.
JANGAN bertingkat FocusArea
di FocusArea
lain.
Tindakan ini akan menyebabkan perilaku navigasi yang tidak ditentukan. Pastikan semua tampilan yang dapat difokuskan
bertingkat dalam FocusArea
.
Contoh FocusArea
di
RotaryPlayground
ditampilkan 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:
- Saat menangani tindakan putar dan dorong,
RotaryService
akan mencari instanceFocusArea
dalam hierarki tampilan. - Saat menerima peristiwa rotasi,
RotaryService
akan memindahkan fokus ke View lain yang dapat mengambil fokus diFocusArea
yang sama. - Saat menerima peristiwa dorongan,
RotaryService
akan memindahkan fokus ke tampilan lain yang dapat mengambil fokus diFocusArea
lain (biasanya berdekatan).
Jika Anda tidak menyertakan FocusAreas
dalam tata letak, tampilan root akan diperlakukan
sebagai area fokus implisit. Pengguna tidak dapat mendorong untuk menavigasi di aplikasi. Sebagai gantinya, mereka akan
memutar semua tampilan yang dapat difokuskan, yang mungkin memadai untuk dialog.
Penyesuaian FocusArea
Dua atribut View standar dapat digunakan untuk menyesuaikan navigasi putar:
android:nextFocusForward
memungkinkan developer aplikasi menentukan urutan rotasi di area fokus. Ini adalah atribut yang sama dengan yang digunakan untuk mengontrol urutan Tab untuk navigasi keyboard. JANGAN gunakan atribut ini untuk membuat loop. Sebagai gantinya, gunakanapp:wrapAround
(lihat di bawah) untuk membuat loop.android:focusedByDefault
memungkinkan developer aplikasi menentukan tampilan fokus default di jendela. JANGAN gunakan atribut ini danapp:defaultFocus
(lihat di bawah) dalamFocusArea
yang sama.
FocusArea
juga menentukan beberapa atribut untuk menyesuaikan navigasi putar.
Area fokus implisit tidak dapat disesuaikan dengan atribut ini.
- (Android 11 QPR3, Android 11 Car,
Android 12)
app:defaultFocus
dapat digunakan untuk menentukan ID tampilan turunan yang dapat difokuskan, yang harus difokuskan saat pengguna mendorong keFocusArea
ini. - (Android 11 QPR3, Android 11 Car,
Android 12)
app:defaultFocusOverridesHistory
dapat disetel ketrue
untuk membuat tampilan yang ditentukan di atas mengambil fokus meskipun dengan histori untuk menunjukkan tampilan lain diFocusArea
ini telah difokuskan. - (Android 12)
Gunakanapp:nudgeLeftShortcut
,app:nudgeRightShortcut
,app:nudgeUpShortcut
, danapp:nudgeDownShortcut
untuk menentukan ID tampilan turunan yang dapat difokuskan, yang harus difokuskan saat pengguna mendorong ke arah tertentu. Untuk mempelajari lebih lanjut, lihat konten untuk pintasan dorong di bawah.(Android 11 QPR3, Android 11 Car, tidak digunakan lagi di Android 12)
app:nudgeShortcut
danapp:nudgeShortcutDirection
hanya mendukung satu pintasan dorong. - (Android 11 QPR3, Android 11 Car,
Android 12)
Untuk mengaktifkan rotasi agar dibungkus diFocusArea
ini,app:wrapAround
dapat disetel ketrue
. Ini biasanya digunakan saat tampilan disusun dalam lingkaran atau oval. - (Android 11 QPR3, Android 11 Car,
Android 12)
Untuk menyesuaikan padding sorotan diFocusArea
ini, gunakanapp:highlightPaddingStart
,app:highlightPaddingEnd
,app:highlightPaddingTop
,app:highlightPaddingBottom
,app:highlightPaddingHorizontal
, danapp:highlightPaddingVertical
. - (Android 11 QPR3, Android 11 Car,
Android 12)
Untuk menyesuaikan batas yang dirasakan dariFocusArea
ini untuk menemukan target dorongan, gunakanapp:startBoundOffset
,app:endBoundOffset
,app:topBoundOffset
,app:bottomBoundOffset
,app:horizontalBoundOffset
, danapp:verticalBoundOffset
. - (Android 11 QPR3, Android 11 Car,
Android 12)
Untuk menentukan IDFocusArea
(atau area) yang berdekatan secara eksplisit dalam rute yang diberikan, gunakanapp:nudgeLeft
,app:nudgeRight
,app:nudgeUp
, danapp:nudgeDown
. Gunakan ini jika penelusuran geometris yang digunakan secara default tidak menemukan target yang diinginkan.
Dorongan biasanya menavigasi di antara FocusAreas. Namun, dengan pintasan dorongan,
dorongan terkadang pertama-tama menavigasi dalam FocusArea
sehingga pengguna mungkin perlu
mendorong dua kali untuk menavigasi ke FocusArea
berikutnya. Pintasan nudge berguna
saat FocusArea
berisi daftar panjang yang diikuti dengan
Floating Action Button,
seperti pada contoh di bawah:

Tanpa pintasan dorong, pengguna harus memutar seluruh daftar untuk mencapai FAB.
Penyesuaian sorotan fokus
Seperti yang disebutkan di atas, RotaryService
dibuat berdasarkan konsep fokus tampilan
yang ada di framework Android. Saat pengguna memutar dan mendorong, RotaryService
akan memindahkan fokus,
memfokuskan satu tampilan dan membatalkan fokus tampilan lainnya. Di Android, saat tampilan difokuskan, jika tampilan:
- Telah menentukan sorotan fokusnya sendiri, Android menggambar sorotan fokus tampilan.
- Tidak menentukan sorotan fokus, dan sorotan fokus default tidak dinonaktifkan, Android akan menggambar sorotan fokus default untuk tampilan.
Aplikasi yang dirancang untuk sentuh biasanya tidak menentukan sorotan fokus yang sesuai.
Sorotan fokus default disediakan oleh framework Android dan dapat diganti
oleh OEM. Developer aplikasi menerimanya saat tema yang mereka gunakan berasal dari
Theme.DeviceDefault
.
Untuk pengalaman pengguna yang konsisten, gunakan sorotan fokus default jika memungkinkan.
Jika Anda memerlukan sorotan fokus berbentuk kustom (misalnya, bulat atau berbentuk pil), atau jika Anda
menggunakan tema yang tidak berasal dari Theme.DeviceDefault
, gunakan resource car-ui-library
untuk menentukan sorotan fokus Anda sendiri untuk setiap tampilan.
Untuk menentukan sorotan fokus kustom untuk tampilan, ubah drawable latar belakang atau latar depan tampilan menjadi drawable yang berbeda saat tampilan difokuskan. Biasanya, Anda akan mengubah latar belakang. Drawable 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 Tebal dalam contoh di atas mengidentifikasi resource yang ditentukan oleh car-ui-library. OEM menggantinya agar konsisten dengan sorotan fokus default yang ditentukan. Hal ini memastikan bahwa warna sorotan fokus, lebar goresan, dan sebagainya tidak berubah saat pengguna beralih antara tampilan dengan sorotan fokus kustom dan tampilan dengan sorotan fokus default. Item terakhir adalah ripple yang digunakan untuk sentuhan. Nilai default yang digunakan untuk resource tebal akan muncul sebagai berikut:

Selain itu, sorotan fokus kustom dipanggil saat tombol diberi warna latar solid untuk menarik perhatian pengguna, seperti pada contoh di bawah. Hal ini dapat membuat sorotan fokus sulit dilihat. Dalam situasi ini, tentukan sorotan fokus kustom menggunakan warna sekunder:
![]() |
- (Android 11 QPR3, Android 11 Car,
Android 12)
car_ui_rotary_focus_fill_secondary_color
car_ui_rotary_focus_stroke_secondary_color
- (Android 12)
car_ui_rotary_focus_pressed_fill_secondary_color
car_ui_rotary_focus_pressed_stroke_secondary_color
Contoh:
![]() |
![]() |
|
Difokuskan, tidak ditekan | Fokus, ditekan |
Scroll putar
Jika aplikasi Anda menggunakan RecyclerView
, Anda HARUS menggunakan
CarUiRecyclerView
sebagai gantinya. Hal ini memastikan bahwa UI Anda konsisten dengan
UI lainnya karena penyesuaian OEM berlaku untuk semua CarUiRecyclerView
.
Jika semua elemen dalam daftar dapat difokuskan, Anda tidak perlu melakukan apa pun. Navigasi rotasi memindahkan fokus melalui elemen dalam daftar dan daftar akan di-scroll agar elemen yang baru difokuskan terlihat.
(Android 11 QPR3, Android 11 Car,
Android 12)
Jika ada campuran elemen yang dapat difokuskan dan tidak dapat difokuskan, atau jika semua elemen tidak dapat difokuskan, Anda dapat mengaktifkan scroll putar, yang memungkinkan
pengguna menggunakan pengontrol putar untuk men-scroll daftar secara bertahap tanpa melewati
item yang tidak dapat difokuskan. Untuk mengaktifkan scroll putar, tetapkan atribut
app:rotaryScrollEnabled
ke true
.
(Android 11 QPR3, Android 11 Car,
Android 12)
Anda dapat mengaktifkan scroll putar di
tampilan yang dapat di-scroll, termasuk avCarUiRecyclerView
, dengan
metode setRotaryScrollEnabled()
di CarUiUtils
. Jika melakukannya,
Anda harus:
- Buat tampilan yang dapat di-scroll dapat difokuskan sehingga dapat difokuskan saat tidak ada tampilan turunan yang dapat difokuskan yang terlihat,
- Nonaktifkan sorotan fokus default pada tampilan yang dapat di-scroll dengan memanggil
setDefaultFocusHighlightEnabled(false)
sehingga tampilan yang dapat di-scroll tidak tampak difokuskan, - Pastikan tampilan yang dapat di-scroll difokuskan sebelum turunannya dengan memanggil
setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS)
. - Proses MotionEvents dengan
SOURCE_ROTARY_ENCODER
danAXIS_VSCROLL
atauAXIS_HSCROLL
untuk menunjukkan jarak yang akan di-scroll dan arah (melalui tanda).
Saat scroll putar diaktifkan di CarUiRecyclerView
dan pengguna memutar
ke area yang tidak memiliki tampilan yang dapat difokuskan, scrollbar akan berubah dari abu-abu menjadi biru, seolah-olah
menunjukkan bahwa scrollbar difokuskan. Anda dapat menerapkan efek serupa jika mau.
MotionEvents sama dengan yang dihasilkan oleh roda scroll pada mouse, kecuali sumbernya.
Mode manipulasi langsung
Biasanya, dorongan dan rotasi menavigasi antarmuka pengguna, sedangkan penekanan tombol Tengah akan melakukan tindakan, meskipun tidak selalu demikian. Misalnya, jika pengguna ingin menyesuaikan volume alarm, mereka dapat menggunakan pengontrol putar untuk membuka penggeser volume, menekan tombol Tengah, memutar pengontrol untuk menyesuaikan volume alarm, lalu menekan tombol Kembali untuk kembali ke navigasi. Hal ini disebut sebagai mode manipulasi langsung (DM). Dalam mode ini, pengontrol rotasi digunakan untuk berinteraksi dengan tampilan secara langsung, bukan untuk menavigasi.
Terapkan DM dengan salah satu dari dua cara. Jika Anda hanya perlu menangani rotasi dan tampilan yang ingin
dimanipulasi merespons ACTION_SCROLL_FORWARD
dan
ACTION_SCROLL_BACKWARD
AccessibilityEvent
dengan tepat, gunakan
mekanisme sederhana. Jika tidak, gunakan mekanisme lanjutan.
Mekanisme sederhana adalah satu-satunya opsi di jendela sistem; aplikasi dapat menggunakan salah satu mekanisme.
Mekanisme sederhana
(Android 11 QPR3, Android 11 Car,
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 difokuskan. Saat dalam mode DM, rotasi akan menjalankan
ACTION_SCROLL_FORWARD
atau ACTION_SCROLL_BACKWARD
dan keluar dari mode DM
saat pengguna menekan tombol Kembali. Mekanisme sederhana ini mengalihkan status tampilan
yang dipilih saat memasuki dan keluar dari mode DM.
Untuk memberikan isyarat visual bahwa pengguna berada dalam mode DM, buat tampilan Anda terlihat berbeda
saat dipilih. Misalnya, ubah latar belakang saat
android:state_selected
adalah true
.
Mekanisme lanjutan
Aplikasi menentukan kapan RotaryService
memasuki dan keluar dari mode DM. Untuk pengalaman pengguna
yang konsisten, menekan tombol Tengah dengan tampilan DM yang difokuskan akan memasuki mode DM
dan tombol Kembali akan keluar dari mode DM. Jika tidak digunakan, tombol Tengah dan/atau dorongan dapat menjadi cara alternatif untuk keluar dari mode DM. Untuk aplikasi seperti Maps, tombol untuk mewakili DM dapat digunakan untuk memasuki mode DM.
Untuk mendukung mode DM lanjutan, tampilan:
- (Android 11 QPR3, Android 11 Car,
Android 12) HARUS memproses peristiwa
KEYCODE_DPAD_CENTER
untuk memasuki mode DM dan memproses peristiwaKEYCODE_BACK
untuk keluar dari mode DM, memanggilDirectManipulationHelper.enableDirectManipulationMode()
dalam setiap kasus. Untuk memproses peristiwa ini, lakukan salah satu tindakan berikut:- Daftarkan
OnKeyListener
.
atau,
- Luaskan tampilan, lalu ganti metode
dispatchKeyEvent()
-nya.
- Daftarkan
- HARUS memproses peristiwa nudge (
KEYCODE_DPAD_UP
,KEYCODE_DPAD_DOWN
,KEYCODE_DPAD_LEFT
, atauKEYCODE_DPAD_RIGHT
) jika tampilan harus menangani nudge. - HARUS memproses
MotionEvent
dan mendapatkan jumlah rotasi diAXIS_SCROLL
jika tampilan ingin menangani rotasi. Ada beberapa cara untuk melakukannya:- Daftarkan
OnGenericMotionListener
. - Luaskan tampilan dan ganti metode
dispatchTouchEvent()
-nya.
- Daftarkan
- Untuk menghindari terjebak dalam mode DM, HARUS keluar dari mode DM saat Fragmen atau Aktivitas yang menjadi milik tampilan tidak interaktif.
- HARUS memberikan isyarat visual untuk menunjukkan bahwa tampilan berada dalam mode DM.
Contoh tampilan kustom yang menggunakan mode DM untuk menggeser dan memperbesar peta diberikan di bawah ini:
/** 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
project RotaryPlayground
.
ActivityView
Saat menggunakan ActivityView:
ActivityView
tidak boleh difokuskan.- (Android 11 QPR3, Android 11 Car,
tidak digunakan lagi di Android 11)
KontenActivityView
HARUS berisiFocusParkingView
sebagai tampilan pertama yang dapat difokuskan, dan atributapp:shouldRestoreFocus
HARUS berupafalse
. - Konten
ActivityView
tidak boleh memiliki tampilanandroid:focusByDefault
.
Bagi pengguna, ActivityViews seharusnya tidak memengaruhi navigasi, kecuali area fokus
tidak dapat menjangkau ActivityViews. Dengan kata lain, Anda tidak dapat memiliki satu area fokus yang
memiliki konten di dalam dan di luar ActivityView
. Jika Anda tidak menambahkan
FocusAreas ke ActivityView
, root hierarki tampilan di
ActivityView
dianggap sebagai area fokus implisit.
Tombol yang beroperasi saat ditahan
Sebagian besar tombol menyebabkan beberapa tindakan saat diklik. Beberapa tombol beroperasi saat ditekan.
Misalnya, tombol Maju Cepat dan Putar Balik biasanya beroperasi saat ditekan. Agar tombol
tersebut mendukung tombol putar, 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 memundurkan) dan menjadwalkan dirinya sendiri untuk
berjalan setelah penundaan.
Mode sentuh
Pengguna dapat menggunakan pengontrol putar untuk berinteraksi dengan head unit di mobil dengan dua cara, baik menggunakan pengontrol putar maupun dengan menyentuh layar. Saat menggunakan pengontrol putar, salah satu tampilan yang dapat difokuskan akan ditandai. Saat menyentuh layar, tidak ada sorotan fokus yang muncul. Pengguna dapat beralih di antara mode input ini kapan saja:
- Putar → sentuh. Saat pengguna menyentuh layar, sorotan fokus akan menghilang.
- Sentuh → putar. Saat pengguna mendorong, memutar, atau menekan tombol Tengah, sorotan fokus akan muncul.
Tombol Kembali dan Layar Utama tidak memengaruhi mode input.
Rotary piggybacks pada konsep
mode sentuh yang ada di Android.
Anda dapat menggunakan
View.isInTouchMode()
untuk menentukan mode input yang digunakan pengguna. Anda dapat menggunakan
OnTouchModeChangeListener
untuk memproses perubahan. Meskipun dapat digunakan untuk menyesuaikan antarmuka pengguna untuk mode input
saat ini, hindari perubahan besar karena dapat mengganggu.
Pemecahan masalah
Dalam aplikasi yang dirancang untuk sentuhan, tampilan bertingkat yang dapat difokuskan biasanya digunakan.
Misalnya, mungkin ada FrameLayout
di sekitar ImageButton
,
yang keduanya dapat difokuskan. Hal ini tidak berbahaya untuk sentuh, tetapi dapat mengakibatkan pengalaman pengguna yang buruk
untuk tombol putar karena pengguna harus memutar pengontrol dua kali untuk berpindah ke
tampilan interaktif berikutnya. Untuk pengalaman pengguna yang baik, Google merekomendasikan agar Anda membuat
tampilan luar atau tampilan dalam dapat difokuskan, tetapi tidak keduanya.
Jika tombol atau tombol beralih kehilangan fokus saat ditekan melalui pengontrol putar, salah satu kondisi berikut mungkin berlaku:
- Tombol atau tombol akses dinonaktifkan (secara singkat atau tanpa batas waktu) karena
tombol ditekan. Dalam kedua kasus tersebut, ada dua cara untuk mengatasinya:
- Biarkan status
android:enabled
sebagaitrue
dan gunakan status kustom untuk membuat tombol atau tombol beralih berwarna abu-abu seperti yang dijelaskan dalam Status Kustom. - Gunakan penampung untuk mengelilingi tombol atau tombol akses dan membuat penampung dapat difokuskan, bukan tombol atau tombol akses. (Pemroses klik harus berada di penampung.)
- Biarkan status
- Tombol atau tombol akses sedang diganti. Misalnya, tindakan yang dilakukan saat tombol
ditekan atau tombol diaktifkan dapat memicu pembaruan tindakan yang tersedia
sehingga tombol baru akan menggantikan tombol yang ada. Ada dua cara untuk mengatasinya:
- Daripada membuat tombol atau tombol akses baru, tetapkan ikon dan/atau teks tombol atau tombol akses yang ada.
- Seperti di atas, tambahkan penampung yang dapat difokuskan di sekitar tombol atau tombol akses.
RotaryPlayground
RotaryPlayground
adalah aplikasi referensi untuk alat rotasi. Gunakan untuk mempelajari cara mengintegrasikan
fitur rotasi ke dalam aplikasi Anda. RotaryPlayground
disertakan dalam build emulator dan dalam
build untuk perangkat yang menjalankan Android Automotive OS (AAOS).
- Repositori
RotaryPlayground
:packages/apps/Car/tests/RotaryPlayground/
- Versi: Android 11 QPR3, Android 11 Car, dan Android 12
Aplikasi RotaryPlayground
menampilkan tab berikut di sebelah kiri:
- Kartu. Uji navigasi di sekitar area fokus, lewati elemen yang tidak dapat difokuskan 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 UI Sys. Uji widget yang mendukung manipulasi langsung di jendela sistem yang hanya mendukung mode manipulasi langsung sederhana.
- Petak. Menguji navigasi dari alat rotasi pola z dengan scroll.
- Notifikasi. Menguji notifikasi pendahuluan yang masuk dan keluar.
- Scroll. Uji scroll melalui campuran konten yang dapat difokuskan dan tidak dapat difokuskan.
- WebView. Uji navigasi melalui link di
WebView
. FocusArea
kustom. Uji penyesuaianFocusArea
:- Wrap-around.
android:focusedByDefault
danapp:defaultFocus
.
- Target dorongan eksplisit.
- Pintasan dorong.
FocusArea
tanpa tampilan yang dapat difokuskan.