เนื้อหาต่อไปนี้มีไว้สำหรับนักพัฒนาแอป
หากต้องการให้แอปรองรับปุ่มหมุน คุณต้องทำดังนี้
- วาง
FocusParkingView
ในเลย์เอาต์กิจกรรมที่เกี่ยวข้อง - อย่าลืมตรวจสอบมุมมองที่โฟกัสได้ (หรือไม่ได้)
- ใช้
FocusArea
เพื่อเลื่อนมุมมองที่โฟกัสได้ทั้งหมด ยกเว้นFocusParkingView
งานแต่ละงานด้านล่างนี้มีรายละเอียดหลังจากที่คุณตั้งค่าสภาพแวดล้อมเพื่อ พัฒนาแอปที่เปิดใช้ด้วยการหมุน
ตั้งค่าตัวควบคุมแบบหมุน
คุณต้องมีตัวควบคุมแบบหมุนก่อนที่จะเริ่มพัฒนาแอปที่เปิดใช้ด้วยปุ่มหมุนได้ หรือแค่การทำงานด้วยตนเอง คุณมีตัวเลือกตามที่อธิบายไว้ด้านล่าง
โปรแกรมจำลอง
source build/envsetup.sh && lunch car_x86_64-userdebug m -j emulator -wipe-data -no-snapshot -writable-system
หรือคุณจะใช้ aosp_car_x86_64-userdebug
ก็ได้
วิธีเข้าถึงตัวควบคุมแบบหมุนจำลอง
- แตะจุด 3 จุดที่ด้านล่างของแถบเครื่องมือ
- เลือกปุ่มหมุนรถยนต์ในหน้าต่างควบคุมแบบขยาย ซึ่งมีดังนี้
แป้นพิมพ์ USB
- เสียบแป้นพิมพ์ USB เข้ากับอุปกรณ์ที่ใช้ Android Automotive OS (AAOS) ในบางกรณี วิธีนี้จะป้องกันไม่ให้แป้นพิมพ์บนหน้าจอปรากฏขึ้น
- ใช้บิลด์
userdebug
หรือeng
- วิธีเปิดใช้การกรองเหตุการณ์สำคัญ
adb shell settings put secure android.car.ROTARY_KEY_EVENT_FILTER 1
- ดูตารางด้านล่างเพื่อหาคีย์ที่สอดคล้องกันสำหรับการดำเนินการแต่ละรายการ
คีย์ การทำงานของปุ่มหมุน Q หมุนทวนเข็มนาฬิกา E หมุนตามเข็มนาฬิกา ก กดไปทางซ้าย D กดไปทางขวา W กดขึ้น อา กดลง F หรือคอมมา ปุ่มกลาง R หรือ Esc ปุ่มย้อนกลับ
คำสั่ง ADB
คุณใช้คําสั่ง car_service
เพื่อแทรกเหตุการณ์การป้อนข้อมูลแบบหมุนได้ คำสั่งเหล่านี้
สามารถเรียกใช้ในอุปกรณ์ที่ใช้ Android Automotive OS (AAOS) หรือในโปรแกรมจําลองได้
คำสั่งเกี่ยวกับบริการรถยนต์ | การป้อนข้อมูลด้วยปุ่มหมุน |
---|---|
adb shell cmd car_service inject-rotary |
หมุนทวนเข็มนาฬิกา |
adb shell cmd car_service inject-rotary -c true |
หมุนตามเข็มนาฬิกา |
adb shell cmd car_service inject-rotary -dt 100 50 |
หมุนทวนเข็มนาฬิกาหลายครั้ง (100 มิลลิวินาทีที่ผ่านมาและ 50 มิลลิวินาทีที่ผ่านมา) |
adb shell cmd car_service inject-key 282 |
กดไปทางซ้าย |
adb shell cmd car_service inject-key 283 |
กดไปทางขวา |
adb shell cmd car_service inject-key 280 |
กดขึ้น |
adb shell cmd car_service inject-key 281 |
กดลง |
adb shell cmd car_service inject-key 23 |
คลิกปุ่มกลาง |
adb shell input keyevent inject-key 4 |
คลิกปุ่มย้อนกลับ |
ตัวควบคุมปุ่มหมุนของ OEM
เมื่อฮาร์ดแวร์ตัวควบคุมแบบหมุนเริ่มทำงานแล้ว นี่เป็นเวลาที่ ที่สมจริง ซึ่งมีประโยชน์อย่างยิ่งสำหรับการทดสอบการหมุนเร็ว
มุมมองที่จอดรถแบบโฟกัส
FocusParkingView
เป็นมุมมองโปร่งใสใน
Car UI Library (car-ui-library)
RotaryService
จะใช้ตำแหน่งนี้เพื่อรองรับการนำทางด้วยตัวควบคุมแบบหมุน
FocusParkingView
ต้องเป็นมุมมองที่โฟกัสได้รายการแรก
ในเลย์เอาต์ ต้องวางนอก FocusArea
ทั้งหมด แต่ละหน้าต่างต้องมี 1 รายการ
FocusParkingView
ถ้าคุณใช้เค้าโครงฐานของ Car-UI-library อยู่แล้ว
ที่มี FocusParkingView
อยู่ คุณไม่จำเป็นต้องเพิ่มอีก
FocusParkingView
ด้านล่างนี้เป็นตัวอย่างของ FocusParkingView
ใน
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>
เหตุผลที่คุณต้องมี FocusParkingView
มีดังนี้
- Android จะไม่ล้างโฟกัสโดยอัตโนมัติเมื่อตั้งค่าโฟกัสในหน้าต่างอื่น หากคุณ
ให้พยายามล้างโฟกัสในหน้าต่างก่อนหน้า Android จะปรับมุมมองในหน้าต่างนั้นใหม่
จะทำให้หน้าต่าง 2 หน้าต่างโฟกัส
พร้อมกัน การเพิ่ม
FocusParkingView
แต่ละหน้าต่างสามารถแก้ปัญหานี้ได้ มุมมองนี้โปร่งใสและมีการไฮไลต์โฟกัสเริ่มต้น ถูกปิดใช้ ดังนั้นผู้ใช้จึงมองไม่เห็น ไม่ว่าจะโฟกัสอยู่หรือไม่ก็ตาม ช่วยปรับโฟกัสเพื่อให้RotaryService
ช่วยกำหนดจุดโฟกัส เพื่อลบไฮไลต์โฟกัส - หากมี
FocusArea
เพียง 1 รายการในหน้าต่างปัจจุบัน กำลังหมุนตัวควบคุม ในFocusArea
จะทำให้RotaryService
ย้ายโฟกัส จากมุมมองด้านขวาไปเป็นมุมมองทางซ้าย (และกลับกัน) กำลังเพิ่มมุมมองนี้ ลงในแต่ละหน้าต่างสามารถช่วยแก้ไขปัญหาได้ เมื่อRotaryService
กําหนดโฟกัส เป้าหมายคือFocusParkingView
ซึ่งสามารถระบุได้ว่าผลสรุปกำลังจะ ซึ่งจะหลีกเลี่ยงการตัดภาพรอบทิศทางโดยไม่ย้ายโฟกัส - เมื่อการควบคุมด้วยปุ่มหมุนเปิดแอป Android จะโฟกัสที่มุมมองที่โฟกัสได้เป็นอันดับแรก
ซึ่งจะเป็น
FocusParkingView
เสมอFocusParkingView
กำหนดมุมมองที่เหมาะสมที่จะมุ่งเน้น แล้วใช้การโฟกัส
มุมมองที่โฟกัสได้
RotaryService
ต่อยอดมาจากเฟรมเวิร์ก
ที่มีอยู่
แนวคิดของการมองภาพย้อนกลับไปตั้งแต่ตอนที่โทรศัพท์มีแป้นพิมพ์จริงและ D-pad
แอตทริบิวต์ android:nextFocusForward
ที่มีอยู่เปลี่ยนเป็นแบบหมุนแล้ว
(ดูการปรับแต่ง FocusArea) แต่
android:nextFocusLeft
android:nextFocusRight
android:nextFocusUp
และ android:nextFocusDown
ไม่ใช่
RotaryService
จะมุ่งเน้นเฉพาะยอดดูที่โฟกัสได้ ยอดดูบางส่วน
เช่น Button
มักจะโฟกัสได้ อื่นๆ เช่น TextView
และ ViewGroup
มักจะไม่ใช่อย่างนั้น มุมมองที่คลิกได้จะโฟกัสได้โดยอัตโนมัติ และการดูจะ
คลิกได้เมื่อมี Listener การคลิก ถ้าตรรกะอัตโนมัตินี้ให้ผลลัพธ์
ความสามารถในการโฟกัส
คุณไม่จำเป็นต้องตั้งค่าความสามารถในการโฟกัสของมุมมองอย่างชัดเจน หากตรรกะอัตโนมัติไม่
ส่งผลให้ความสามารถในการโฟกัสที่ต้องการ ให้ตั้งค่าแอตทริบิวต์ android:focusable
เป็น
true
หรือ false
หรือตั้งค่าความสามารถในการโฟกัสของมุมมองแบบเป็นโปรแกรมด้วย
View.setFocusable(boolean)
RotaryService
ต้องมีการแสดงผลจึงจะเห็นได้
มีคุณสมบัติตรงตามข้อกำหนดต่อไปนี้
- โฟกัสได้
- เปิดใช้
- แสดง
- มีค่าความกว้างและความสูงที่ไม่ใช่ 0
หากข้อมูลพร็อพเพอร์ตี้ไม่เป็นไปตามข้อกำหนดเหล่านี้ทั้งหมด เช่น ปุ่มที่โฟกัสได้แต่ปิดใช้
ผู้ใช้ไม่สามารถใช้ปุ่มหมุนควบคุมเพื่อโฟกัสได้ หากคุณต้องการโฟกัส
การดูที่ปิดไปแล้ว
ลองใช้สถานะที่กำหนดเองแทน android:state_enabled
เพื่อควบคุมวิธีการ
มุมมองปรากฏขึ้นโดยไม่ระบุว่า Android ควรพิจารณาปิดใช้มุมมองนี้ แอปของคุณให้ข้อมูล
ผู้ใช้ว่าเหตุใดการดูจึงถูกปิดใช้เมื่อแตะ ส่วนถัดไปจะอธิบายถึงวิธีการดังกล่าว
สถานะที่กำหนดเอง
วิธีเพิ่มสถานะที่กำหนดเอง
- วิธีเพิ่มแอตทริบิวต์ที่กำหนดเอง
ในมุมมองของคุณ เช่น หากต้องการเพิ่มสถานะที่กำหนดเอง
state_rotary_enabled
ลงใน ดูชั้นเรียนของCustomView
ใช้:<declare-styleable name="CustomView"> <attr name="state_rotary_enabled" format="boolean" /> </declare-styleable>
- หากต้องการติดตามสถานะนี้ ให้เพิ่มตัวแปรอินสแตนซ์ลงในข้อมูลพร็อพเพอร์ตี้พร้อมกับเมธอดตัวเข้าถึง ดังนี้
private boolean mRotaryEnabled; public boolean getRotaryEnabled() { return mRotaryEnabled; } public void setRotaryEnabled(boolean rotaryEnabled) { mRotaryEnabled = rotaryEnabled; }
- หากต้องการอ่านค่าของแอตทริบิวต์เมื่อสร้างมุมมองของคุณ ให้ทำดังนี้
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView); mRotaryEnabled = a.getBoolean(R.styleable.CustomView_state_rotary_enabled);
- ในคลาสการแสดงผล ให้ลบล้างเมธอด
onCreateDrawableState()
แล้ว เพิ่มสถานะที่กำหนดเองได้ตามความเหมาะสม ดังตัวอย่างต่อไปนี้@Override protected int[] onCreateDrawableState(int extraSpace) { if (mRotaryEnabled) extraSpace++; int[] drawableState = super.onCreateDrawableState(extraSpace); if (mRotaryEnabled) { mergeDrawableStates(drawableState, { R.attr.state_rotary_enabled }); } return drawableState; }
- ทำให้เครื่องจัดการการคลิกของมุมมองทำงานแตกต่างออกไปตามสถานะ ตัวอย่างเช่น พารามิเตอร์
เครื่องจัดการการคลิกอาจไม่ดำเนินการใดๆ หรืออาจแสดงข้อความโทสต์เมื่อ
mRotaryEnabled
คือfalse
- หากต้องการทำให้ปุ่มถูกปิดใช้งาน ให้ใช้ที่ถอนออกได้ในพื้นหลังของมุมมอง
app:state_rotary_enabled
จากราคาเต็มandroid:state_enabled
หากยังไม่มี ให้เพิ่มรายการต่อไปนี้xmlns:app="http://schemas.android.com/apk/res-auto"
- หากปิดใช้มุมมองในเลย์เอาต์ใดก็ตาม ให้แทนที่
android:enabled="false"
ด้วยapp:state_rotary_enabled="false"
จากนั้นเพิ่มเนมสเปซapp
เหมือนดังข้างต้น - หากมุมมองของคุณถูกปิดใช้งานแบบเป็นโปรแกรม ให้แทนที่การเรียกไปยัง
setEnabled()
ที่มีการโทรไปยังsetRotaryEnabled()
พื้นที่โฟกัส
ใช้ FocusAreas
เพื่อแบ่งพาร์ติชันมุมมองที่โฟกัสได้เป็นบล็อกเพื่อทำการนำทาง
ง่ายขึ้นและสอดคล้องกับแอปอื่นๆ ตัวอย่างเช่น หากแอปของคุณมีแถบเครื่องมือ แถบเครื่องมือ
ควรอยู่ใน FocusArea
แยกต่างหากจากแอปอื่นๆ ของคุณ แถบแท็บและ
ควรแยกองค์ประกอบการนำทางอื่นๆ ออกจากส่วนอื่นๆ ของแอปด้วย รายการขนาดใหญ่
โดยทั่วไปควรมี FocusArea
เป็นของตัวเอง หากไม่เป็นเช่นนั้น ผู้ใช้ต้องหมุนเวียนไปเรื่อยๆ
รายการทั้งหมดเพื่อเข้าถึงมุมมองบางรายการ
FocusArea
เป็นคลาสย่อยของ LinearLayout
ใน car-ui-library
เมื่อเปิดใช้ฟีเจอร์นี้ FocusArea
จะวาดไฮไลต์เมื่อ
องค์ประกอบสืบทอดจะเน้น ดูข้อมูลเพิ่มเติมได้ที่
โฟกัสการปรับแต่งไฮไลต์
เมื่อสร้างบล็อกการนำทางในไฟล์การออกแบบ หากคุณต้องการใช้
LinearLayout
เป็นคอนเทนเนอร์สำหรับบล็อกนั้นๆ ให้ใช้ FocusArea
แทน
หรือรวมบล็อกไว้ใน FocusArea
อย่าฝัง FocusArea
ไว้ใน FocusArea
อื่น
เพราะจะนำไปสู่ลักษณะการไปยังส่วนต่างๆ ที่ไม่ได้กำหนด ตรวจสอบว่ามุมมองที่โฟกัสได้ทั้งหมด
ฝังอยู่ใน FocusArea
ตัวอย่างของ FocusArea
ใน
RotaryPlayground
แสดงอยู่ด้านล่าง
<com.android.car.ui.FocusArea android:layout_margin="16dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:singleLine="true"> </EditText> </com.android.car.ui.FocusArea>
FocusArea
ทำงานดังต่อไปนี้
- เมื่อจัดการการทำงานด้วยการหมุนและการกระตุ้น
RotaryService
จะค้นหาอินสแตนซ์ ของFocusArea
ในลำดับชั้นการแสดงผล - เมื่อได้รับเหตุการณ์การหมุน
RotaryService
จะย้ายโฟกัสไปยังอื่น มุมมองที่โฟกัสได้ในFocusArea
เดียวกัน - เมื่อได้รับเหตุการณ์การกระตุ้นเตือน
RotaryService
จะย้ายโฟกัสไปยังมุมมองอื่น ที่สามารถโฟกัสในอีกFocusArea
(โดยทั่วไปจะอยู่ติดกัน)
หากคุณไม่รวม FocusAreas
ใดๆ ไว้ในเลย์เอาต์ ระบบจะถือว่ามุมมองรูท
เป็นส่วนที่เน้นโดยนัย ผู้ใช้ไม่สามารถกระตุ้นการนำทางในแอปได้ แต่พวกเขาจะ
เปลี่ยนมุมมองที่โฟกัสได้ทั้งหมด ซึ่งอาจเพียงพอสำหรับกล่องโต้ตอบ
การปรับแต่ง FocusArea
คุณสามารถใช้แอตทริบิวต์มุมมองมาตรฐาน 2 รายการเพื่อปรับแต่งการนำทางด้วยปุ่มหมุนได้ ดังนี้
android:nextFocusForward
อนุญาตให้นักพัฒนาแอประบุการหมุนเวียน ตามลำดับที่สำคัญ นี่เป็นแอตทริบิวต์เดียวกับที่ใช้ควบคุมลำดับแท็บสำหรับ การไปยังส่วนต่างๆ ด้วยแป้นพิมพ์ อย่าใช้แอตทริบิวต์นี้ในการสร้างการวนซ้ำ แต่ให้ใช้app:wrapAround
(ดูด้านล่าง) เพื่อสร้างวนซ้ำแทนandroid:focusedByDefault
ช่วยให้นักพัฒนาแอปสามารถระบุ มุมมองโฟกัสเริ่มต้นในหน้าต่าง อย่าใช้แอตทริบิวต์นี้และapp:defaultFocus
(ดูด้านล่าง) ในFocusArea
เดียวกัน
FocusArea
ยังกำหนดแอตทริบิวต์บางรายการเพื่อปรับแต่งการนำทางด้วยปุ่มหมุนด้วย
ไม่สามารถปรับแต่งพื้นที่โฟกัสโดยนัยด้วยแอตทริบิวต์เหล่านี้ได้
- (Android 11 QPR3, รถยนต์ Android 11
Android 12)
app:defaultFocus
สามารถใช้เพื่อ ระบุรหัสของมุมมององค์ประกอบสืบทอดที่โฟกัสได้ ซึ่งควรมุ่งเน้นเมื่อผู้ใช้ กระตุ้นไปที่FocusArea
นี้ - (Android 11 QPR3, รถยนต์ Android 11
Android 12)
app:defaultFocusOverridesHistory
ตั้งค่าเป็นtrue
เพื่อให้มุมมองที่ระบุด้านบนเป็นจุดโฟกัสได้ ประวัติเพื่อระบุว่ามีการเน้นที่มุมมองอื่นในFocusArea
นี้ - (Android 12)
ใช้app:nudgeLeftShortcut
,app:nudgeRightShortcut
app:nudgeUpShortcut
และapp:nudgeDownShortcut
เพื่อระบุรหัสของมุมมององค์ประกอบสืบทอดที่โฟกัสได้ ซึ่งควรโฟกัสเมื่อ สะกิดผู้ใช้ไปในทิศทางที่กำหนด หากต้องการเรียนรู้เพิ่มเติม โปรดดูเนื้อหาของ ปุ่มลัดด้านล่าง(Android 11 QPR3, รถยนต์ Android 11 เลิกใช้งานใน Android 12)
app:nudgeShortcut
และapp:nudgeShortcutDirection
รองรับทางลัดการกระตุ้นเตือนเพียง 1 รายการเท่านั้น - (Android 11 QPR3, รถยนต์ Android 11
Android 12)
เมื่อต้องการเปิดใช้การหมุนเพื่อวนรอบในFocusArea
นี้app:wrapAround
ตั้งค่าเป็นtrue
ได้ ซึ่งมักใช้เมื่อจัดเรียงมุมมองในลักษณะ เป็นวงกลมหรือวงรี - (Android 11 QPR3, รถยนต์ Android 11
Android 12)
วิธีปรับระยะห่างจากขอบของไฮไลต์FocusArea
นี้ ใช้app:highlightPaddingStart
app:highlightPaddingEnd
app:highlightPaddingTop
app:highlightPaddingBottom
,app:highlightPaddingHorizontal
และapp:highlightPaddingVertical
- (Android 11 QPR3, รถยนต์ Android 11
Android 12)
หากต้องการปรับขอบเขตที่รับรู้ของFocusArea
นี้เพื่อค้นหาเป้าหมายการกระตุ้นเตือน ใช้app:startBoundOffset
,app:endBoundOffset
app:topBoundOffset
app:bottomBoundOffset
app:horizontalBoundOffset
และapp:verticalBoundOffset
- (Android 11 QPR3, รถยนต์ Android 11
Android 12)
หากต้องการระบุรหัสของFocusArea
(หรือพื้นที่) ที่อยู่ติดกันในเส้นทางที่กำหนดapp:nudgeLeft
,app:nudgeRight
,app:nudgeUp
และapp:nudgeDown
ใช้ตัวเลือกนี้เมื่อมีการใช้การค้นหาทางเรขาคณิตเป็นค่าเริ่มต้น ไม่พบเป้าหมายที่ต้องการ
การกระตุ้นเตือนมักเป็นเส้นทางระหว่าง FocusAreas แต่ด้วยทางลัดการกระตุ้นเตือน
บางครั้งการกระตุ้นเตือนจะไปยังส่วนต่างๆ ภายใน FocusArea
ก่อนเพื่อให้ผู้ใช้อาจจําเป็น
เพื่อเลื่อน 2 ครั้งเพื่อไปยัง FocusArea
ถัดไป แป้นพิมพ์ลัดของการกระตุ้นเตือนมีประโยชน์
เมื่อ FocusArea
มีรายการที่ยาวตามด้วย
ปุ่มการทำงานแบบลอย
ตามตัวอย่างด้านล่าง
หากไม่มีทางลัดการกระตุ้นเตือน ผู้ใช้จะต้องหมุนเวียนไปเรื่อยๆ จากรายการทั้งหมดเพื่อเข้าถึง FAB
โฟกัสการปรับแต่งไฮไลต์
ดังที่ระบุไว้ข้างต้น RotaryService
สร้างขึ้นจากแนวคิดที่มีอยู่ของเฟรมเวิร์ก Android
ดูโฟกัส เมื่อผู้ใช้หมุนและเลื่อน RotaryService
จะย้ายโฟกัสไปรอบๆ
โดยโฟกัสมุมมองหนึ่งและไม่โฟกัสอีกมุมมอง ใน Android เมื่อโฟกัสที่มุมมอง สิ่งที่จะเกิดขึ้นมีดังนี้
- ได้ระบุการไฮไลต์จุดโฟกัสของตัวเอง Android จะวาดการไฮไลต์การโฟกัสของมุมมอง
- ไม่ได้ระบุการไฮไลต์จุดโฟกัส และไม่มีการปิดใช้ไฮไลต์โฟกัสเริ่มต้น จะวาดไฮไลต์โฟกัสเริ่มต้นสำหรับมุมมอง
แอปที่ออกแบบมาสำหรับการสัมผัสมักจะไม่ได้ระบุการโฟกัสที่เหมาะสม
เฟรมเวิร์กของ Android จะไฮไลต์โฟกัสเริ่มต้นและลบล้างได้
โดย OEM นักพัฒนาแอปจะได้รับการแจ้งเตือนเมื่อธีมที่ใช้อยู่มาจากธีม
Theme.DeviceDefault
ใช้ไฮไลต์โฟกัสเริ่มต้นเมื่อเป็นไปได้เพื่อให้ผู้ใช้ได้รับประสบการณ์ที่สอดคล้องกัน
ถ้าต้องการไฮไลต์ที่มีรูปทรงที่กำหนดเอง (เช่น ทรงกลมหรือทรงยา) หรือหาก
โดยใช้ธีมที่ไม่ได้มาจาก Theme.DeviceDefault
ให้ใช้ Car-ui-library
เพื่อกำหนดจุดมุ่งเน้นของคุณเองสำหรับแต่ละมุมมอง
หากต้องการระบุไฮไลต์การโฟกัสแบบกำหนดเองสำหรับมุมมอง ให้เปลี่ยนพื้นหลังหรือพื้นหน้าที่ถอนออกได้ ของมุมมอง เป็นโฆษณาที่ถอนออกได้ ซึ่งจะแตกต่างออกไปเมื่อมีการโฟกัสที่มุมมองนั้น โดยปกติแล้วคุณจะต้องเปลี่ยน พื้นหลัง รายการต่อไปนี้สามารถใช้เป็นพื้นหลังสำหรับมุมมองสี่เหลี่ยมจัตุรัส จะสร้างไฮไลต์ที่เน้นวงกลม
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_focused="true" android:state_pressed="true"> <shape android:shape="oval"> <solid android:color="@color/car_ui_rotary_focus_pressed_fill_color"/> <stroke android:width="@dimen/car_ui_rotary_focus_pressed_stroke_width" android:color="@color/car_ui_rotary_focus_pressed_stroke_color"/> </shape> </item> <item android:state_focused="true"> <shape android:shape="oval"> <solid android:color="@color/car_ui_rotary_focus_fill_color"/> <stroke android:width="@dimen/car_ui_rotary_focus_stroke_width" android:color="@color/car_ui_rotary_focus_stroke_color"/> </shape> </item> <item> <ripple...> ... </ripple> </item> </selector>
(Android 11 QPR3, รถยนต์ Android 11 Android 12) การอ้างอิงทรัพยากรที่เป็นตัวหนาในตัวอย่าง ด้านบนจะระบุทรัพยากรที่กำหนดโดย car-ui-library OEM จะลบล้างค่านี้เพื่อให้สอดคล้องกัน พร้อมไฮไลต์การโฟกัสที่เป็นค่าเริ่มต้นที่กำหนดไว้ ซึ่งช่วยให้แน่ใจว่าสีไฮไลต์ที่โฟกัส ความกว้างของเส้นโครงร่าง และอื่นๆ จะไม่เปลี่ยนแปลงเมื่อผู้ใช้ไปยังมุมมองต่างๆ ที่มีโฟกัสที่กำหนดเอง ไฮไลต์และมุมมองที่มีการไฮไลต์โฟกัสเริ่มต้น รายการสุดท้ายเป็นระลอกคลื่นที่ใช้สำหรับการแตะ ค่าเริ่มต้นที่ใช้สำหรับทรัพยากรที่เป็นตัวหนาจะแสดงดังนี้
นอกจากนี้ จะมีการไฮไลต์การโฟกัสแบบกำหนดเองเมื่อแสดงปุ่มที่ทึบ เพื่อดึงดูดความสนใจของผู้ใช้ ดังเช่นในตัวอย่างด้านล่าง สิ่งนี้สามารถทำให้ ไฮไลต์ที่มองไม่เห็นยาก ในกรณีนี้ ให้ระบุการไฮไลต์จุดโฟกัสที่กำหนดเองโดยใช้ สีรอง:
- (Android 11 QPR3, รถยนต์ Android 11
Android 12)
car_ui_rotary_focus_fill_secondary_color
car_ui_rotary_focus_stroke_secondary_color
- (Android 12)
car_ui_rotary_focus_pressed_fill_secondary_color
car_ui_rotary_focus_pressed_stroke_secondary_color
เช่น
โฟกัส ไม่ได้กด | โฟกัส กด |
การเลื่อนแบบหมุน
หากแอปใช้ RecyclerView
คุณควรใช้
CarUiRecyclerView
แทน ซึ่งจะทำให้ UI ของคุณสอดคล้องกับ
อื่นๆ เนื่องจากการปรับแต่งของ OEM มีผลกับ CarUiRecyclerView
ทั้งหมด
หากองค์ประกอบในลิสต์สามารถโฟกัสได้ทั้งหมด คุณก็ไม่ต้องดำเนินการใดๆ การนำทางด้วยปุ่มหมุนจะย้ายโฟกัสผ่านองค์ประกอบในรายการ แล้วรายการจะเลื่อน เพื่อแสดงองค์ประกอบที่โฟกัสใหม่
(Android 11 QPR3, รถยนต์ Android 11
Android 12)
ถ้ามีทั้งการโฟกัสและโฟกัสไม่ได้
หรือหากองค์ประกอบทั้งหมดไม่สามารถโฟกัสได้ คุณสามารถเปิดใช้การเลื่อนแบบหมุน ซึ่งช่วยให้
ให้ใช้ปุ่มหมุนควบคุมเพื่อค่อยๆ เลื่อนดูรายการโดยไม่ข้าม
รายการที่ไม่สามารถโฟกัสได้ หากต้องการเปิดใช้การเลื่อนแบบหมุน ให้ตั้งค่า app:rotaryScrollEnabled
เป็น true
(Android 11 QPR3, รถยนต์ Android 11
Android 12)
คุณสามารถเปิดใช้งานการเลื่อนแบบหมุนได้
มุมมองแบบเลื่อนได้ ซึ่งรวมถึง AvCarUiRecyclerView
ที่มีองค์ประกอบ
setRotaryScrollEnabled()
เมธอดใน CarUiUtils
หากคุณทำเช่นนั้น
คุณต้องทำดังนี้
- ทำให้มุมมองที่เลื่อนได้โฟกัสได้ เพื่อที่จะสามารถโฟกัสได้เมื่อไม่มีการโฟกัส มุมมององค์ประกอบสืบทอดที่โฟกัสได้จะปรากฏ
- ปิดใช้การไฮไลต์โฟกัสเริ่มต้นในมุมมองที่เลื่อนได้ด้วยการเรียกใช้
setDefaultFocusHighlightEnabled(false)
เพื่อให้มุมมองที่เลื่อนได้ ดูเหมือนจะไม่มีสมาธิ - ตรวจสอบว่าได้โฟกัสที่มุมมองที่เลื่อนได้ก่อนรายการระดับล่างด้วยการเรียก
setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS)
- ฟังเหตุการณ์การเคลื่อนไหวด้วย
SOURCE_ROTARY_ENCODER
และAXIS_VSCROLL
หรือAXIS_HSCROLL
เพื่อระบุระยะทางที่จะเลื่อนและ ทิศทาง (ผ่านป้าย)
เมื่อเปิดใช้การเลื่อนแบบหมุนใน CarUiRecyclerView
และผู้ใช้หมุน
ไปยังบริเวณที่ไม่มีมุมมองที่โฟกัสได้ แถบเลื่อนจะเปลี่ยนจากสีเทาเป็นสีน้ำเงิน เหมือนกับว่า
เพื่อบอกสถานะว่าแถบเลื่อนมีโฟกัสอยู่ คุณสามารถนำเอฟเฟกต์ที่คล้ายกันนี้ไปใช้ได้หากต้องการ
MotionEvent จะเหมือนกับเหตุการณ์ที่สร้างโดยล้อเลื่อนของเมาส์ ยกเว้นแหล่งที่มา
โหมดการจัดการโดยตรง
โดยปกติแล้ว การกระตุ้นเตือนและการหมุนจะไปยังส่วนต่างๆ ของอินเทอร์เฟซผู้ใช้ ในขณะที่การกดปุ่มตรงกลาง ดำเนินการบางอย่าง แต่อาจไม่เป็นเช่นนี้เสมอไป เช่น หากผู้ใช้ต้องการปรับ ระดับเสียงปลุก ก็อาจใช้ตัวควบคุมแบบหมุนเพื่อไปยังแถบเลื่อนระดับเสียง แล้วกด ปุ่มตรงกลาง หมุนตัวควบคุมเพื่อปรับระดับเสียงปลุก แล้วกดปุ่มย้อนกลับ เพื่อกลับไปยังการนำทาง วิธีนี้เรียกว่าโหมดการจัดการโดยตรง (DM) ด้วยวิธีนี้ ตัวควบคุมปุ่มหมุนจะใช้ในการโต้ตอบกับมุมมองโดยตรงแทนการนำทาง
ใช้ DM ด้วย 1 ใน 2 วิธีต่อไปนี้ ถ้าคุณแค่ต้องจัดการกับการหมุนและมุมมองที่ต้องการเท่านั้น
เพื่อตอบสนอง ACTION_SCROLL_FORWARD
และ
ACTION_SCROLL_BACKWARD
AccessibilityEvent
อย่างเหมาะสม ให้ใช้
กลไกที่เรียบง่าย หรือใช้กลไกขั้นสูง
กลไกแบบง่ายเป็นเพียงตัวเลือกเดียวในหน้าต่างระบบ จะใช้กลไกใดก็ได้
กลไกที่ใช้ง่าย
(Android 11 QPR3, รถยนต์ Android 11
Android 12)
แอปของคุณควรเรียกใช้
DirectManipulationHelper.setSupportsRotateDirectly(View view, boolean enable)
RotaryService
จะจดจำเมื่อผู้ใช้อยู่ในโหมด DM และเข้าสู่โหมด DM เมื่อผู้ใช้อยู่ในโหมด DM
กดปุ่มกลางขณะที่มุมมองถูกโฟกัส เมื่ออยู่ในโหมด DM การหมุนจะทํางาน
ACTION_SCROLL_FORWARD
หรือ ACTION_SCROLL_BACKWARD
และออกจากโหมด DM
เมื่อผู้ใช้กดปุ่มย้อนกลับ กลไกแบบง่ายจะเปิด/ปิดสถานะที่เลือก
มุมมองเมื่อเข้าและออกจากโหมด DM
หากต้องการให้ภาพที่ผู้ใช้อยู่ในโหมด DM คุณต้องทำให้มุมมองของคุณปรากฏแตกต่างออกไป
เมื่อเลือกไว้ เช่น เปลี่ยนพื้นหลังเมื่อ
android:state_selected
คือtrue
กลไกขั้นสูง
แอปจะระบุเวลาที่ RotaryService
จะเข้าและออกจากโหมด DM เพื่อความสม่ำเสมอ
ประสบการณ์ของผู้ใช้ การกดปุ่มตรงกลางที่โฟกัสด้วยมุมมอง DM ควรเข้าสู่โหมด DM
และปุ่มย้อนกลับควรออกจากโหมด DM หากไม่ได้ใช้ปุ่มกลางและ/หรือการกระตุ้นเตือน
สามารถใช้เป็นทางเลือกในการออกจากโหมด DM สำหรับแอป เช่น Maps ปุ่มที่แสดง
DM ใช้เพื่อเข้าสู่โหมด DM ได้
หากต้องการรองรับโหมด DM ขั้นสูง ให้ใช้มุมมองดังนี้
- (Android 11 QPR3, รถยนต์ Android 11
Android 12) ต้องฟัง
KEYCODE_DPAD_CENTER
เหตุการณ์ที่จะเข้าสู่โหมด DM และรอเหตุการณ์KEYCODE_BACK
เพื่อออกจากโหมด DM จะเรียกDirectManipulationHelper.enableDirectManipulationMode()
ในแต่ละกรณี หากต้องการฟังเหตุการณ์เหล่านี้ ให้ทําอย่างใดอย่างหนึ่งต่อไปนี้- ลงทะเบียน
OnKeyListener
หรือ
- ขยายมุมมองแล้วลบล้างเมธอด
dispatchKeyEvent()
ของมุมมองนั้น
- ลงทะเบียน
- ควรฟังเหตุการณ์การกระตุ้นเตือน (
KEYCODE_DPAD_UP
,KEYCODE_DPAD_DOWN
KEYCODE_DPAD_LEFT
หรือKEYCODE_DPAD_RIGHT
) หากมุมมองควร ที่กระตุ้นเตือน - ควรฟัง
MotionEvent
วินาทีและรับการนับรอบในAXIS_SCROLL
หากมุมมองต้องการจัดการการหมุน ซึ่งทำได้หลายวิธี ดังนี้- ลงทะเบียน
OnGenericMotionListener
- ขยายมุมมองและลบล้างเมธอด
dispatchTouchEvent()
- ลงทะเบียน
- เพื่อหลีกเลี่ยงการค้างอยู่ในโหมด DM ให้ออกจากโหมด DM เมื่อ Fragment หรือกิจกรรมในมุมมอง เป็นของ ไม่มีการโต้ตอบ
- ควรมีสัญลักษณ์ภาพเพื่อระบุว่ามุมมองอยู่ในโหมด DM
ดูตัวอย่างมุมมองที่กำหนดเองซึ่งใช้โหมด DM เพื่อเลื่อนและซูมแผนที่ได้ที่ด้านล่าง
/** Whether this view is in DM mode. */ private boolean mInDirectManipulationMode;
/** Initializes the view. Called by the constructors. */ private void init() { setOnKeyListener((view, keyCode, keyEvent) -> { boolean isActionUp = keyEvent.getAction() == KeyEvent.ACTION_UP; switch (keyCode) { // Always consume KEYCODE_DPAD_CENTER and KEYCODE_BACK events. case KeyEvent.KEYCODE_DPAD_CENTER: if (!mInDirectManipulationMode && isActionUp) { mInDirectManipulationMode = true; DirectManipulationHelper.enableDirectManipulationMode(this, true); setSelected(true); // visually indicate DM mode } return true; case KeyEvent.KEYCODE_BACK: if (mInDirectManipulationMode && isActionUp) { mInDirectManipulationMode = false; DirectManipulationHelper.enableDirectManipulationMode(this, false); setSelected(false); } return true; // Consume controller nudge events only when in DM mode. // When in DM mode, nudges pan the map. case KeyEvent.KEYCODE_DPAD_UP: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(0f, -10f); return true; case KeyEvent.KEYCODE_DPAD_DOWN: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(0f, 10f); return true; case KeyEvent.KEYCODE_DPAD_LEFT: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(-10f, 0f); return true; case KeyEvent.KEYCODE_DPAD_RIGHT: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(10f, 0f); return true; // Don't consume other key events. default: return false; } });
// When in DM mode, rotation zooms the map. setOnGenericMotionListener(((view, motionEvent) -> { if (!mInDirectManipulationMode) return false; float scroll = motionEvent.getAxisValue(MotionEvent.AXIS_SCROLL); zoom(10 * scroll); return true; })); }
@Override public void onPause() { if (mInDirectManipulationMode) { // To ensure that the user doesn't get stuck in DM mode, disable DM mode // when the fragment is not interactive (e.g., a dialog shows up). mInDirectManipulationMode = false; DirectManipulationHelper.enableDirectManipulationMode(this, false); } super.onPause(); }
ดูตัวอย่างเพิ่มเติมได้ใน
RotaryPlayground
โปรเจ็กต์
มุมมองกิจกรรม
เมื่อใช้มุมมองกิจกรรม ให้ทำดังนี้
ActivityView
ไม่ควรโฟกัสได้- (Android 11 QPR3, รถยนต์ Android 11
เลิกใช้งานแล้วใน Android 11)
เนื้อหาของActivityView
ต้องมีFocusParkingView
เป็นมุมมองที่โฟกัสได้ครั้งแรก และapp:shouldRestoreFocus
ต้องเป็นfalse
- เนื้อหาของ
ActivityView
ไม่ควรมี ยอดดูandroid:focusByDefault
ครั้ง
สำหรับผู้ใช้นั้น ActivityViews ไม่ควรส่งผลใดๆ ต่อการนำทาง ยกเว้นการโฟกัสนั้น
พื้นที่ไม่สามารถขยาย ActivityViews ได้ กล่าวคือ คุณไม่สามารถมี
ด้านที่มุ่งเน้นเฉพาะ
มีเนื้อหาภายในและภายนอก ActivityView
หากไม่เพิ่ม
FocusAreas ใดๆ ก็ตามไปยัง ActivityView
ซึ่งเป็นรูทของลำดับชั้นการแสดงผลใน
ActivityView
ถือเป็นด้านที่มุ่งเน้นโดยนัย
ปุ่มที่ทำงานเมื่อกดค้างไว้
ปุ่มส่วนใหญ่ทำให้มีการทำงานบางอย่างเมื่อคลิก ปุ่มบางปุ่มจะทำงานเมื่อกดค้างไว้แทน
ตัวอย่างเช่น โดยปกติปุ่มกรอไปข้างหน้าและกรอกลับจะทำงานเมื่อกดค้างไว้ เพื่อให้ข้อมูลดังกล่าว
ปุ่มหมุนรองรับปุ่มหมุน ฟัง KEYCODE_DPAD_CENTER
KeyEvents
ดังนี้
mButton.setOnKeyListener((v, keyCode, event) -> { if (keyCode != KEYCODE_DPAD_CENTER) { return false; } if (event.getAction() == ACTION_DOWN) { mButton.setPressed(true); mHandler.post(mRunnable); } else { mButton.setPressed(false); mHandler.removeCallbacks(mRunnable); } return true; });
ซึ่ง mRunnable
จะดำเนินการบางอย่าง (เช่น กรอกลับ) และตั้งเวลาให้
เรียกใช้หลังจากความล่าช้า
โหมดสัมผัส
ผู้ใช้สามารถใช้ตัวควบคุมแบบหมุนเพื่อโต้ตอบกับเครื่องเล่นวิทยุในรถยนต์ได้ 2 วิธีดังนี้ จะใช้ตัวควบคุมแบบหมุนหรือแตะหน้าจอก็ได้ เมื่อใช้ตัวควบคุมแบบหมุน มุมมองที่โฟกัสได้มุมมองหนึ่งคือมุมมองที่มีการไฮไลต์ ไม่มีการไฮไลต์โฟกัสเมื่อแตะหน้าจอ จะปรากฏขึ้น ผู้ใช้สามารถสลับระหว่างโหมดป้อนข้อมูลเหล่านี้ได้ทุกเมื่อ
- หมุน → แตะ เมื่อผู้ใช้แตะหน้าจอ ไฮไลต์โฟกัสจะหายไป
- แตะ → ปุ่มหมุน เมื่อผู้ใช้เลื่อน หมุน หรือกดปุ่มกลาง ไฮไลต์ที่โฟกัสจะปรากฏขึ้น
ปุ่มย้อนกลับและปุ่มหน้าแรกจะไม่มีผลกับโหมดป้อนข้อมูล
การผูกโยงกับแต่ละแบบในความคิดของ Android
โหมดสัมผัส
คุณสามารถใช้
View.isInTouchMode()
เพื่อระบุว่าผู้ใช้กำลังใช้โหมดป้อนข้อมูลใด คุณสามารถใช้
OnTouchModeChangeListener
เพื่อฟังการเปลี่ยนแปลง ขณะที่การตั้งค่านี้สามารถใช้ปรับแต่งอินเทอร์เฟซผู้ใช้ของคุณสำหรับ
โหมดป้อนข้อมูล โปรดหลีกเลี่ยงการเปลี่ยนแปลงที่สำคัญ เพราะอาจทำให้เกิดความน่าตกใจ
การแก้ปัญหา
ในแอปที่ออกแบบมาเพื่อการแตะ เป็นเรื่องปกติที่จะมีมุมมองที่โฟกัสได้ที่ซ้อนกันอยู่
ตัวอย่างเช่น อาจมี FrameLayout
รอบๆ ImageButton
ซึ่งสามารถโฟกัสทั้ง 2 แบบได้ ซึ่งไม่อันตรายต่อการสัมผัส แต่อาจส่งผลทางลบ
ประสบการณ์ของผู้ใช้สำหรับปุ่มหมุนเพราะผู้ใช้ต้องหมุนตัวควบคุม 2 ครั้งเพื่อเคลื่อนที่
ก็จะมีมุมมองแบบอินเทอร์แอกทีฟถัดไป เพื่อให้ผู้ใช้ได้รับประสบการณ์การใช้งานที่ดี Google ขอแนะนำให้คุณทำอย่างใดอย่างหนึ่งต่อไปนี้
มุมมองด้านนอกหรือด้านในที่โฟกัสได้ แต่ทำทั้ง 2 อย่างไม่ได้
หากปุ่มหรือสวิตช์สูญเสียโฟกัสเมื่อกดผ่านตัวควบคุมแบบหมุน หนึ่งใน อาจมีเงื่อนไขเหล่านี้
- ปุ่มหรือสวิตช์ถูกปิดใช้งาน (เป็นเวลาสั้นๆ หรือไม่มีกำหนด) เนื่องจาก
มีการกดปุ่มอยู่ ไม่ว่าจะเป็นกรณีใดก็ตาม คุณสามารถจัดการกับเรื่องนี้ได้ 2 วิธี ดังนี้
- คงสถานะ
android:enabled
ไว้เป็นtrue
และใช้ เพื่อทำให้ปุ่มหรือสวิตช์เป็นสีเทาตามที่อธิบายไว้ใน สถานะที่กำหนดเอง - ใช้คอนเทนเนอร์เพื่อล้อมรอบปุ่มหรือสวิตช์และทำให้โฟกัสของคอนเทนเนอร์ได้ แทนปุ่มหรือสวิตช์ (Listener การคลิกต้องอยู่บนคอนเทนเนอร์)
- คงสถานะ
- มีการเปลี่ยนปุ่มหรือสวิตช์ ตัวอย่างเช่น การดำเนินการที่เกิดขึ้นเมื่อปุ่ม
มีการกดหรือสวิตช์ถูกเปิดไว้อาจทริกเกอร์การรีเฟรชของการทำงานที่ใช้ได้
ทำให้ปุ่มใหม่มาแทนที่ปุ่มที่มีอยู่ มี 2 วิธีในการแก้ไขปัญหานี้ ได้แก่
- แทนที่จะสร้างปุ่มหรือสวิตช์ใหม่ ให้ตั้งค่าไอคอนและ/หรือข้อความของ ปุ่มหรือสวิตช์ที่มีอยู่
- เพิ่มคอนเทนเนอร์ที่โฟกัสได้รอบปุ่มหรือสวิตช์ดังข้างต้น
สนามเด็กเล่นแบบหมุน
RotaryPlayground
เป็นแอปอ้างอิงสำหรับปุ่มหมุน ใช้รายงานนี้เพื่อดูวิธีผสานรวม
คุณลักษณะแบบหมุนลงในแอปของคุณ RotaryPlayground
รวมอยู่ในบิลด์ของโปรแกรมจำลองและใน
บิลด์สําหรับอุปกรณ์ที่ใช้ Android Automotive OS (AAOS)
- ที่เก็บ
RotaryPlayground
รายการ:packages/apps/Car/tests/RotaryPlayground/
- เวอร์ชัน: Android 11 QPR3, Android 11 Car, และ Android 12
แอป RotaryPlayground
จะแสดงแท็บต่อไปนี้ทางด้านซ้าย
- การ์ด ทดสอบการนำทางรอบๆ พื้นที่โฟกัสโดยข้ามองค์ประกอบที่โฟกัสไม่ได้ และการป้อนข้อความ
- การชักจูงทางตรง วิดเจ็ตทดสอบที่รองรับทั้งแบบง่ายและขั้นสูง โหมดการจัดการโดยตรง แท็บนี้มีไว้สำหรับการควบคุมโดยตรงภายใน หน้าต่างแอป
- การจัดการ UI ของ Sys วิดเจ็ตทดสอบที่รองรับการควบคุมโดยตรง ในหน้าต่างระบบที่รองรับเฉพาะโหมดการจัดการโดยตรงอย่างง่ายเท่านั้น
- ตารางกริด ทดสอบการนำทางด้วยปุ่มหมุนแบบ Z ด้วยการเลื่อน
- การแจ้งเตือน ทดสอบการสะกิดการแจ้งเตือนล่วงหน้าเข้าและออก
- เลื่อน ทดสอบการเลื่อนผ่านการผสมผสานระหว่างโฟกัสได้และโฟกัสไม่ได้ เนื้อหา
- WebView ทดสอบการนำทางผ่านลิงก์ใน
WebView
- กำหนดเอง
FocusArea
ทดสอบการปรับแต่งFocusArea
:- ใส่ได้ครบถ้วน
android:focusedByDefault
และapp:defaultFocus
- เป้าหมายการกระตุ้นเตือนที่ชัดเจน
- เลื่อนทางลัด
FocusArea
โดยไม่มีมุมมองที่โฟกัสได้