المواد التالية مخصصة لمطوري التطبيقات.
لجعل دعم تطبيقك دوارًا، يجب عليك:
- ضع
FocusParkingView
في تخطيط النشاط المعني. - تأكد من طرق العرض القابلة للتركيز (أو غير القابلة للتركيز).
- استخدم
FocusArea
s للالتفاف حول جميع طرق العرض القابلة للتركيز، باستثناءFocusParkingView
.
تم تفصيل كل مهمة من هذه المهام أدناه، بعد أن تقوم بإعداد بيئتك لتطوير التطبيقات التي تدعم الدوار.
إعداد وحدة تحكم دوارة
قبل أن تتمكن من البدء في تطوير التطبيقات التي تدعم الدوارة، تحتاج إما إلى وحدة تحكم دوارة أو بديل. لديك الخيارات الموضحة أدناه.
محاكي
source build/envsetup.sh && lunch car_x86_64-userdebug m -j emulator -wipe-data -no-snapshot -writable-system
يمكنك أيضًا استخدام aosp_car_x86_64-userdebug
.
للوصول إلى وحدة التحكم الدوارة التي تمت محاكاتها:
- اضغط على النقاط الثلاث في أسفل شريط الأدوات:
- حدد دوارة السيارة في نافذة عناصر التحكم الموسعة:
لوحة مفاتيح USB
- قم بتوصيل لوحة مفاتيح USB بجهازك الذي يعمل بنظام التشغيل Android Automotive OS (AAOS)، وفي بعض الحالات، يمنع هذا ظهور لوحة المفاتيح على الشاشة.
- استخدم
userdebug
أوeng
build. - تمكين تصفية الأحداث الرئيسية:
adb shell settings put secure android.car.ROTARY_KEY_EVENT_FILTER 1
- انظر الجدول أدناه للعثور على المفتاح المقابل لكل إجراء:
مفتاح عمل دوار س تدوير عكس اتجاه عقارب الساعة ه تدوير في اتجاه عقارب الساعة أ دفع اليسار د ادفع لليمين دبليو ادفع للأعلى س ادفع للأسفل F أو فاصلة زر الوسط ص أو خروج زر العودة
أوامر بنك التنمية الآسيوي
يمكنك استخدام أوامر 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
FocusParkingView
هو عرض شفاف في مكتبة واجهة مستخدم السيارة (car-ui-library) . تستخدمه RotaryService
لدعم التنقل بوحدة التحكم الدوارة. يجب أن يكون FocusParkingView
هو العرض الأول القابل للتركيز في التخطيط. ويجب وضعه خارج جميع FocusArea
. يجب أن تحتوي كل نافذة على FocusParkingView
واحد. إذا كنت تستخدم بالفعل التخطيط الأساسي لمكتبة واجهة المستخدم للسيارة، والذي يحتوي على 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 بإعادة تركيز العرض في تلك النافذة، مما يؤدي إلى التركيز على نافذتين في وقت واحد. يمكن أن تؤدي إضافة
FocusParkingView
إلى كل نافذة إلى حل هذه المشكلة. يتميز هذا العرض بالشفافية ويتم تعطيل تمييز التركيز الافتراضي الخاص به، بحيث يكون غير مرئي للمستخدم سواء تم التركيز عليه أم لا. يمكن أن يستغرق التركيز حتى تتمكنRotaryService
من إيقاف التركيز عليه لإزالة تمييز التركيز. - إذا كان هناك
FocusArea
واحد فقط في النافذة الحالية، فإن تدوير وحدة التحكم فيFocusArea
يؤدي إلى قيامRotaryService
بنقل التركيز من العرض الموجود على اليمين إلى العرض الموجود على اليسار (والعكس صحيح). يمكن أن تؤدي إضافة هذا العرض إلى كل نافذة إلى حل المشكلة. عندما تحددRotaryService
أن هدف التركيز هوFocusParkingView
، يمكنها تحديد أن الالتفاف على وشك الحدوث عند هذه النقطة يتجنب الالتفاف من خلال عدم تحريك التركيز. - عندما يقوم عنصر التحكم الدوار بتشغيل تطبيق ما، يركز Android على العرض الأول القابل للتركيز، والذي يكون دائمًا
FocusParkingView
. يحددFocusParkingView
العرض الأمثل للتركيز عليه ثم يطبق التركيز.
مناظر قابلة للتركيز
تعتمد RotaryService
على المفهوم الحالي لإطار عمل Android الخاص بتركيز العرض، والذي يعود تاريخه إلى الوقت الذي كانت فيه الهواتف تحتوي على لوحات مفاتيح فعلية ولوحات D. تمت إعادة استخدام السمة android:nextFocusForward
الحالية للاستخدام الدوار (راجع تخصيص FocusArea )، لكن android:nextFocusLeft
و android:nextFocusRight
و android:nextFocusUp
و android:nextFocusDown
ليست كذلك.
تركز RotaryService
فقط على طرق العرض القابلة للتركيز. عادةً ما تكون بعض طرق العرض، مثل Button
s، قابلة للتركيز. البعض الآخر، مثل TextView
s و ViewGroup
s، عادةً لا يكون كذلك. تكون العروض القابلة للنقر قابلة للتركيز تلقائيًا وتكون العروض قابلة للنقر عليها تلقائيًا عندما يكون بها مستمع للنقرات. إذا أدى هذا المنطق التلقائي إلى إمكانية التركيز المطلوبة، فلن تحتاج إلى تعيين إمكانية التركيز على العرض بشكل صريح. إذا لم ينتج عن المنطق التلقائي إمكانية التركيز المطلوبة، فاضبط السمة android:focusable
على true
أو false
، أو اضبط قابلية التركيز على العرض برمجيًا باستخدام View.setFocusable(boolean)
. لكي تركز RotaryService
عليها، يجب أن يستوفي العرض المتطلبات التالية:
- قابل للتركيز
- ممكّن
- مرئي
- لديك قيم غير صفرية للعرض والارتفاع
إذا كان العرض لا يفي بجميع هذه المتطلبات، على سبيل المثال زر قابل للتركيز ولكنه معطل، فلن يتمكن المستخدم من استخدام عنصر التحكم الدوار للتركيز عليه. إذا كنت تريد التركيز على طرق العرض المعطلة، ففكر في استخدام حالة مخصصة بدلاً من 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
في مكتبة واجهة المستخدم للسيارة. عند تمكين هذه الميزة، تقوم 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
في التخطيط الخاص بك، فسيتم التعامل مع العرض الجذر كمنطقة تركيز ضمنية. لا يمكن للمستخدم دفعه للتنقل في التطبيق. بدلاً من ذلك، سيتم تدويرها عبر جميع طرق العرض القابلة للتركيز، والتي قد تكون كافية لمربعات الحوار.
تخصيص منطقة التركيز
يمكن استخدام سمتين قياسيتين للعرض لتخصيص التنقل الدوار:
-
android:nextFocusForward
يسمح لمطوري التطبيقات بتحديد ترتيب التناوب في منطقة التركيز. هذه هي نفس السمة المستخدمة للتحكم في ترتيب علامات التبويب للتنقل عبر لوحة المفاتيح. لا تستخدم هذه السمة لإنشاء حلقة. بدلاً من ذلك، استخدمapp:wrapAround
(انظر أدناه) لإنشاء حلقة. -
android:focusedByDefault
يسمح لمطوري التطبيقات بتحديد عرض التركيز الافتراضي في النافذة. لا تستخدم هذه السمة وapp:defaultFocus
(انظر أدناه) في نفسFocusArea
.
تحدد FocusArea
أيضًا بعض السمات لتخصيص التنقل الدوار. لا يمكن تخصيص مناطق التركيز الضمنية باستخدام هذه السمات.
- ( اندرويد 11 QPR3، اندرويد 11 سيارة، اندرويد 12 )
يمكن استخدامapp:defaultFocus
لتحديد معرف العرض التنازلي القابل للتركيز، والذي يجب التركيز عليه عندما يدفع المستخدم إلىFocusArea
. - ( اندرويد 11 QPR3، اندرويد 11 سيارة، اندرويد 12 )
app:defaultFocusOverridesHistory
يمكن تعيينه علىtrue
لجعل العرض المحدد أعلاه يتم التركيز عليه حتى لو كان السجل يشير إلى عرض آخر فيFocusArea
تم التركيز عليه. - ( أندرويد 12 )
استخدمapp:nudgeLeftShortcut
وapp:nudgeRightShortcut
وapp:nudgeUpShortcut
وapp:nudgeDownShortcut
لتحديد معرف العرض التنازلي القابل للتركيز، والذي يجب التركيز عليه عندما يدفع المستخدم في اتجاه معين. لمعرفة المزيد، راجع محتوى اختصارات الدفع أدناه.( Android 11 QPR3، Android 11 Car، تم إهماله في Android 12 )
app:nudgeShortcut
والتطبيقapp:nudgeShortcutDirection
يدعم اختصار دفع واحد فقط. - ( اندرويد 11 QPR3، اندرويد 11 سيارة، اندرويد 12 )
لتمكين التدوير للالتفاف فيFocusArea
هذه، يمكن ضبطapp:wrapAround
علىtrue
. يتم استخدام هذا عادةً عندما يتم ترتيب العروض في شكل دائرة أو بيضاوية. - ( اندرويد 11 QPR3، اندرويد 11 سيارة، اندرويد 12 )
لضبط مساحة التمييز فيFocusArea
هذه، استخدمapp:highlightPaddingStart
وapp:highlightPaddingEnd
وapp:highlightPaddingTop
وapp:highlightPaddingBottom
وapp:highlightPaddingHorizontal
وapp:highlightPaddingVertical
. - ( اندرويد 11 QPR3، اندرويد 11 سيارة، اندرويد 12 )
لضبط الحدود المتصورةFocusArea
هذه للعثور على هدف دفع، استخدمapp:startBoundOffset
app:endBoundOffset
وapp:topBoundOffset
وapp:bottomBoundOffset
app:horizontalBoundOffset
وapp:verticalBoundOffset
. - ( اندرويد 11 QPR3، اندرويد 11 سيارة، اندرويد 12 )
لتحديد معرفFocusArea
(أو المناطق) المجاورة بشكل صريح في الاتجاهات المحددة، استخدمapp:nudgeLeft
وapp:nudgeRight
وapp:nudgeUp
وapp:nudgeDown
. استخدم هذا عندما لا يجد البحث الهندسي المستخدم افتراضيًا الهدف المطلوب.
يتنقل الدفع عادةً بين مناطق التركيز. ولكن باستخدام اختصارات الدفع، أحيانًا ما يتم التنقل أولاً داخل FocusArea
بحيث قد يحتاج المستخدم إلى الدفع مرتين للانتقال إلى FocusArea
التالية. تكون اختصارات الدفع مفيدة عندما تحتوي FocusArea
على قائمة طويلة متبوعة بزر إجراء عائم ، كما في المثال أدناه:
بدون اختصار الدفع، سيتعين على المستخدم التنقل عبر القائمة بأكملها للوصول إلى FAB.
تخصيص تسليط الضوء على التركيز
كما هو مذكور أعلاه، تعتمد RotaryService
على مفهوم التركيز على العرض الحالي لإطار عمل Android. عندما يقوم المستخدم بالتدوير والدفع، تقوم RotaryService
بتحريك التركيز، مع التركيز على عرض واحد وإلغاء التركيز على عرض آخر. في Android، عندما يتم التركيز على العرض، إذا كان العرض:
- قام Android بتحديد تسليط الضوء على التركيز الخاص به، حيث يقوم Android برسم تسليط الضوء على العرض.
- لا يحدد تمييز التركيز، ولا يتم تعطيل تمييز التركيز الافتراضي، ويرسم Android تمييز التركيز الافتراضي للعرض.
عادةً لا تحدد التطبيقات المصممة للمس نقاط التركيز المناسبة.
يتم توفير تمييز التركيز الافتراضي بواسطة إطار عمل Android ويمكن تجاوزه بواسطة OEM. يتلقاها مطورو التطبيقات عندما يكون السمة التي يستخدمونها مشتقة من Theme.DeviceDefault
.
للحصول على تجربة مستخدم متسقة، اعتمد على تمييز التركيز الافتراضي كلما أمكن ذلك. إذا كنت بحاجة إلى تمييز تركيز ذو شكل مخصص (على سبيل المثال، دائري أو على شكل قرص)، أو إذا كنت تستخدم سمة غير مشتقة من Theme.DeviceDefault
، فاستخدم موارد مكتبة واجهة المستخدم للسيارة لتحديد تمييز التركيز الخاص بك لـ كل عرض.
لتحديد تمييز تركيز مخصص لعرض ما، قم بتغيير الخلفية أو المقدمة الرسومية للعرض إلى رسم يختلف عندما يتم التركيز على العرض. عادة، يمكنك تغيير الخلفية. الرسم التالي، إذا تم استخدامه كخلفية لعرض مربع، سينتج تمييزًا دائريًا للتركيز:
<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 ) تحدد مراجع الموارد الغامقة في العينة أعلاه الموارد المحددة بواسطة مكتبة واجهة المستخدم للسيارة. يتجاوز OEM هذه لتكون متسقة مع تمييز التركيز الافتراضي الذي يحددونه. يضمن هذا عدم تغيير لون تمييز التركيز وعرض الحد وما إلى ذلك عندما يتنقل المستخدم بين طريقة عرض ذات تمييز تركيز مخصص وعرض مع تمييز التركيز الافتراضي. العنصر الأخير هو تموج يستخدم للمس. تظهر القيم الافتراضية المستخدمة للموارد الغامقة كما يلي:
بالإضافة إلى ذلك، يتم استدعاء تمييز التركيز المخصص عندما يتم إعطاء زر لون خلفية خالص لجذب انتباه المستخدم، كما في المثال أدناه. قد يؤدي ذلك إلى صعوبة رؤية التركيز البؤري. في هذه الحالة، حدد تمييز التركيز المخصص باستخدام الألوان الثانوية :
- ( اندرويد 11 QPR3، اندرويد 11 سيارة، اندرويد 12 )
car_ui_rotary_focus_fill_secondary_color
car_ui_rotary_focus_stroke_secondary_color
- ( أندرويد 12 )
car_ui_rotary_focus_pressed_fill_secondary_color
car_ui_rotary_focus_pressed_stroke_secondary_color
على سبيل المثال:
مركزة وليست مضغوطة | ركزت وضغطت |
التمرير الدوار
إذا كان تطبيقك يستخدم RecyclerView
s، فيجب عليك استخدام CarUiRecyclerView
s بدلاً من ذلك. وهذا يضمن أن واجهة المستخدم الخاصة بك متوافقة مع الآخرين لأن تخصيص الشركة المصنعة للمعدات الأصلية (OEM) ينطبق على جميع برامج CarUiRecyclerView
.
إذا كانت جميع العناصر الموجودة في قائمتك قابلة للتركيز، فلن تحتاج إلى القيام بأي شيء آخر. ينقل التنقل الدوار التركيز عبر العناصر الموجودة في القائمة ويتم تمرير القائمة لجعل العنصر الذي تم التركيز عليه حديثًا مرئيًا.
( اندرويد 11 QPR3، اندرويد 11 سيارة، اندرويد 12 )
إذا كان هناك مزيج من العناصر القابلة للتركيز والعناصر غير القابلة للتركيز، أو إذا كانت جميع العناصر غير قابلة للتركيز، فيمكنك تمكين التمرير الدوار، مما يسمح للمستخدم باستخدام وحدة التحكم الدوارة للتمرير تدريجيًا خلال القائمة دون تخطي العناصر غير القابلة للتركيز. لتمكين التمرير الدوار، قم بتعيين السمة app:rotaryScrollEnabled
على true
.
( اندرويد 11 QPR3، اندرويد 11 سيارة، اندرويد 12 )
يمكنك تمكين التمرير الدوار في أي عرض قابل للتمرير، بما في ذلك av CarUiRecyclerView
، باستخدام طريقة setRotaryScrollEnabled()
في CarUiUtils
. إذا قمت بذلك، فأنت بحاجة إلى:
- اجعل العرض القابل للتمرير قابلاً للتركيز بحيث يمكن التركيز عليه عندما لا تكون أي من طرق العرض التابعة القابلة للتركيز مرئية،
- قم بتعطيل تمييز التركيز الافتراضي في العرض القابل للتمرير عن طريق استدعاء
setDefaultFocusHighlightEnabled(false)
بحيث لا يبدو العرض القابل للتمرير مركّزًا، - تأكد من أن العرض القابل للتمرير يتم التركيز عليه قبل العناصر التابعة له عن طريق استدعاء
setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS)
. - استمع إلى MotionEvents باستخدام
SOURCE_ROTARY_ENCODER
وإماAXIS_VSCROLL
أوAXIS_HSCROLL
للإشارة إلى المسافة المطلوب التمرير والاتجاه (من خلال العلامة).
عندما يتم تمكين التمرير الدوار في CarUiRecyclerView
ويدور المستخدم إلى منطقة لا توجد بها طرق عرض قابلة للتركيز، يتغير شريط التمرير من اللون الرمادي إلى الأزرق، كما لو كان للإشارة إلى تركيز شريط التمرير. يمكنك تنفيذ تأثير مماثل إذا أردت.
أحداث الحركة هي نفسها التي تم إنشاؤها بواسطة عجلة التمرير على الماوس، باستثناء المصدر.
وضع التلاعب المباشر
عادةً، تتنقل الدفعات والتدوير عبر واجهة المستخدم، بينما يضغط الزر الأوسط على اتخاذ إجراء، على الرغم من أن هذا ليس هو الحال دائمًا. على سبيل المثال، إذا أراد المستخدم ضبط مستوى صوت المنبه، فيمكنه استخدام وحدة التحكم الدوارة للانتقال إلى شريط تمرير مستوى الصوت، والضغط على الزر الأوسط، وتدوير وحدة التحكم لضبط مستوى صوت المنبه، ثم الضغط على الزر "رجوع" للعودة إلى التنقل . ويشار إلى هذا باسم وضع المعالجة المباشرة (DM) . في هذا الوضع، يتم استخدام وحدة التحكم الدوارة للتفاعل مع العرض مباشرة بدلاً من التنقل.
قم بتنفيذ DM بإحدى طريقتين. إذا كنت تحتاج فقط إلى التعامل مع التدوير وكان العرض الذي تريد معالجته يستجيب لـ ACTION_SCROLL_FORWARD
و ACTION_SCROLL_BACKWARD
AccessibilityEvent
s بشكل مناسب، فاستخدم الآلية البسيطة . خلاف ذلك، استخدم الآلية المتقدمة .
الآلية البسيطة هي الخيار الوحيد في نوافذ النظام؛ يمكن للتطبيقات استخدام أي من الآليتين.
آلية بسيطة
( اندرويد 11 QPR3، اندرويد 11 سيارة، اندرويد 12 )
يجب أن يستدعي تطبيقك DirectManipulationHelper.setSupportsRotateDirectly(View view, boolean enable)
. تتعرف RotaryService
عندما يكون المستخدم في وضع DM ويدخل في وضع DM عندما يضغط المستخدم على الزر الأوسط أثناء تركيز العرض. عندما تكون في وضع DM، تقوم عمليات التدوير بتنفيذ ACTION_SCROLL_FORWARD
أو ACTION_SCROLL_BACKWARD
وتخرج من وضع DM عندما يضغط المستخدم على زر الرجوع. تعمل الآلية البسيطة على تبديل حالة العرض المحددة عند الدخول إلى وضع DM والخروج منه.
لتوفير إشارة مرئية بأن المستخدم في وضع DM، اجعل طريقة العرض الخاصة بك تظهر بشكل مختلف عند تحديدها. على سبيل المثال، قم بتغيير الخلفية عندما يكون android:state_selected
true
.
آلية متقدمة
يحدد التطبيق متى تدخل RotaryService
وتخرج من وضع DM. للحصول على تجربة مستخدم متسقة، يجب أن يؤدي الضغط على الزر الأوسط مع التركيز على عرض DM إلى الدخول في وضع DM ويجب أن يخرج الزر الخلفي من وضع DM. إذا لم يتم استخدام الزر الأوسط و/أو الدفع، فيمكن أن تكون طرقًا بديلة للخروج من وضع DM. بالنسبة لتطبيقات مثل الخرائط، يمكن استخدام زر يمثل DM للدخول إلى وضع DM.
لدعم وضع DM المتقدم، عرض:
- ( Android 11 QPR3، Android 11 Car، 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
s والحصول على عدد التدوير فيAXIS_SCROLL
إذا كان العرض يريد التعامل مع التدوير. هناك عدة طرق للقيام بذلك:- قم بتسجيل
OnGenericMotionListener
. - قم بتوسيع العرض وتجاوز طريقة
dispatchTouchEvent()
الخاصة به.
- قم بتسجيل
- لتجنب الوقوع في وضع DM، يجب الخروج من وضع DM عندما لا يكون الجزء أو النشاط الذي ينتمي إليه العرض تفاعليًا.
- يجب أن يوفر إشارة مرئية للإشارة إلى أن العرض في وضع 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 Car، تم إهماله في Android 11 )
يجب أن تحتوي محتوياتActivityView
علىFocusParkingView
كأول عرض قابل للتركيز، ويجب أن تكون السمةapp:shouldRestoreFocus
الخاصة بهfalse
. - يجب ألا تحتوي محتويات
ActivityView
على طرق عرضandroid:focusByDefault
.
بالنسبة للمستخدم، يجب ألا يكون لـ ActivityViews أي تأثير على التنقل باستثناء أن مناطق التركيز لا يمكن أن تمتد إلى ActivityViews. بمعنى آخر، لا يمكن أن يكون لديك منطقة تركيز واحدة تحتوي على محتوى داخل وخارج ActivityView
. إذا لم تقم بإضافة أي مناطق تركيز إلى ActivityView
، فإن جذر التسلسل الهرمي للعرض في ActivityView
يعتبر منطقة تركيز ضمنية.
الأزرار التي تعمل عند الضغط عليها
تتسبب معظم الأزرار في حدوث بعض الإجراءات عند النقر عليها. تعمل بعض الأزرار عند الضغط عليها بدلاً من ذلك. على سبيل المثال، يعمل الزران Fast Forward وRewind عادةً عند الضغط باستمرار عليهما. لجعل هذه الأزرار تدعم الدوارة، استمع إلى KEYCODE_DPAD_CENTER
KeyEvents
كما يلي:
mButton.setOnKeyListener((v, keyCode, event) -> { if (keyCode != KEYCODE_DPAD_CENTER) { return false; } if (event.getAction() == ACTION_DOWN) { mButton.setPressed(true); mHandler.post(mRunnable); } else { mButton.setPressed(false); mHandler.removeCallbacks(mRunnable); } return true; });
حيث يتخذ mRunnable
إجراءً (مثل إعادة اللف) ويقوم بجدولة نفسه ليتم تشغيله بعد تأخير.
وضع اللمس
يمكن للمستخدمين استخدام وحدة التحكم الدوارة للتفاعل مع الوحدة الرئيسية في السيارة بطريقتين، إما باستخدام وحدة التحكم الدوارة أو عن طريق لمس الشاشة. عند استخدام وحدة التحكم الدوارة، يتم تمييز إحدى طرق العرض القابلة للتركيز. عند لمس الشاشة، لا يظهر أي تمييز للتركيز. يمكن للمستخدم التبديل بين أوضاع الإدخال هذه في أي وقت:
- الروتاري → اللمس. عندما يلمس المستخدم الشاشة، يختفي تمييز التركيز.
- المس ← دوارة. عندما يقوم المستخدم بدفع الزر الأوسط أو تدويره أو الضغط عليه، يظهر تمييز التركيز.
ليس لزري الرجوع والصفحة الرئيسية أي تأثير على وضع الإدخال.
ظهورات دوارة على مفهوم Android الحالي لوضع اللمس . يمكنك استخدام View.isInTouchMode()
لتحديد وضع الإدخال الذي يستخدمه المستخدم. يمكنك استخدام OnTouchModeChangeListener
للاستماع إلى التغييرات. بينما يمكن استخدام هذا لتخصيص واجهة المستخدم الخاصة بك لوضع الإدخال الحالي، تجنب أي تغييرات كبيرة لأنها قد تكون مربكة.
استكشاف الأخطاء وإصلاحها
في التطبيق المصمم للعمل باللمس، من الشائع أن تكون هناك طرق عرض متداخلة قابلة للتركيز. على سبيل المثال، قد يكون هناك FrameLayout
حول ImageButton
، وكلاهما قابل للتركيز. لا يضر هذا باللمس ولكنه قد يؤدي إلى تجربة مستخدم سيئة بالنسبة للدوران لأنه يجب على المستخدم تدوير وحدة التحكم مرتين للانتقال إلى العرض التفاعلي التالي. للحصول على تجربة مستخدم جيدة، توصي Google بجعل العرض الخارجي أو العرض الداخلي قابلاً للتركيز، ولكن ليس كليهما.
إذا فقد زر أو مفتاح التركيز عند الضغط عليه من خلال وحدة التحكم الدوارة، فقد ينطبق أحد الشروط التالية:
- يتم تعطيل الزر أو المفتاح (لفترة وجيزة أو إلى أجل غير مسمى) بسبب الضغط على الزر. وفي كلتا الحالتين، هناك طريقتان لمعالجة هذا:
- اترك الحالة
android:enabled
على أنهاtrue
واستخدم حالة مخصصة لتظليل الزر أو التبديل باللون الرمادي كما هو موضح في الحالة المخصصة . - استخدم حاوية لإحاطة الزر أو المفتاح واجعل الحاوية قابلة للتركيز بدلاً من الزر أو المفتاح. (يجب أن يكون مستمع النقر موجودًا على الحاوية.)
- اترك الحالة
- يتم استبدال الزر أو المفتاح. على سبيل المثال، قد يؤدي الإجراء المتخذ عند الضغط على الزر أو تبديل المفتاح إلى تحديث الإجراءات المتاحة مما يؤدي إلى استبدال الأزرار الجديدة بالأزرار الموجودة. هناك طريقتان لمعالجة هذا:
- بدلاً من إنشاء زر أو مفتاح تبديل جديد، قم بتعيين رمز و/أو نص الزر أو المفتاح الموجود.
- كما هو مذكور أعلاه، قم بإضافة حاوية قابلة للتركيز حول الزر أو المفتاح.
ملعب الروتاري
RotaryPlayground
هو تطبيق مرجعي للروتاري. استخدمه لتتعلم كيفية دمج الميزات الدوارة في تطبيقاتك. يتم تضمين RotaryPlayground
في إصدارات المحاكي وفي تصميمات الأجهزة التي تعمل بنظام التشغيل Android Automotive OS (AAOS).
- مستودع
RotaryPlayground
:packages/apps/Car/tests/RotaryPlayground/
- الإصدارات: Android 11 QPR3 وAndroid 11 Car وAndroid 12
يعرض تطبيق RotaryPlayground
علامات التبويب التالية على اليسار:
- بطاقات. اختبر التنقل حول مناطق التركيز، وتخطي العناصر غير القابلة للتركيز وإدخال النص.
- التلاعب المباشر. أدوات الاختبار التي تدعم وضع المعالجة المباشرة البسيط والمتقدم. علامة التبويب هذه مخصصة للمعالجة المباشرة داخل نافذة التطبيق.
- التلاعب بواجهة مستخدم النظام. أدوات الاختبار التي تدعم المعالجة المباشرة في نوافذ النظام حيث يتم دعم وضع المعالجة المباشرة البسيطة فقط.
- شبكة. اختبار التنقل الدوار بنمط z مع التمرير.
- إشعار. اختبار الدفع داخل وخارج الإخطارات الفردية.
- قم بالتمرير. اختبر التمرير عبر مزيج من المحتوى القابل للتركيز وغير القابل للتركيز.
- عرض ويب. اختبار التنقل عبر الروابط في
WebView
. -
FocusArea
المخصصة تخصيصFocusArea
الاختبارية:- التفاف حولها.
-
android:focusedByDefault
وapp:defaultFocus
. - أهداف تحفيزية صريحة.
- اختصارات الدفع.
-
FocusArea
بدون طرق عرض قابلة للتركيز.