החומר הבא מיועד למפתחי אפליקציות.
כדי שהאפליקציה תתמוך בחוגה, צריך:
- צריך להציב
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
.
כדי לגשת לאמולציה של בקר החוגה:
- לוחצים על סמל שלוש הנקודות שמוצג בתחתית סרגל הכלים:
- בוחרים באפשרות חוגה של מכונית בחלון הפקדים המורחבים:
מקלדת USB
- מחברים למכשיר מקלדת USB שמותקנת בו מערכת ההפעלה Android Automotive OS (AAOS). במקרים מסוימים, ההגדרה הזו מונעת את הצגת המקלדת שמופיעה במסך.
- צריך להשתמש ב-build של
userdebug
אוeng
. - הפעלת סינון האירועים המרכזיים:
adb shell settings put secure android.car.ROTARY_KEY_EVENT_FILTER 1
- בטבלה שבהמשך אפשר למצוא את המפתח המתאים לכל פעולה:
מפתח פעולות סיבוביות Q סיבוב נגד כיוון השעון E סיבוב בכיוון השעון A הסט שמאלה D הסט ימינה W הסט כלפי מעלה S הסט כלפי מטה F או פסיק הלחצן המרכזי R או Esc לחצן 'הקודם'
פקודות ADB
אפשר להשתמש בפקודות car_service
כדי להחדיר אירועים של קלט חוגה. הפקודות האלה
אפשר להפעיל אותן במכשירים עם Android Automotive OS (AAOS) או באמולטור.
פקודות car_service | חוגה לקלט הנתונים |
---|---|
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
מתבסס על
קיים
התמקדות בתצוגה, עוד מהימים שבהם היו לטלפונים מקלדות פיזיות ומחיצות D.
המאפיין android:nextFocusForward
הקיים משמש מחדש לחוגה
(ראו התאמה אישית של אזור המיקוד), אבל
android:nextFocusLeft
, android:nextFocusRight
,
android:nextFocusUp
ו-android:nextFocusDown
לא.
RotaryService
מתמקד רק בתצוגות שניתן להתמקד בהן. חלק מהצפיות
כמו Button
,
בדרך כלל ניתן להתמקד בהם. סוגים אחרים, כמו TextView
וViewGroup
,
בדרך כלל לא. תצוגות שניתנות ללחיצה ניתנות למיקוד באופן אוטומטי והצפיות
קליקביליות כשיש להם האזנה לקליקים. אם הלוגיקה האוטומטית הזאת
אתם לא צריכים להגדיר בצורה מפורשת את יכולת המיקוד של התצוגה. אם הלוגיקה האוטומטית לא
כדי להשיג את רמת המיקוד הרצויה, צריך להגדיר את המאפיין 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>
- כדי לעקוב אחרי המצב הזה, מוסיפים לתצוגה משתנה של מופע בשילוב עם methods של Accessor:
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; }
- שינוי הביצועים של מטפל הקליקים בתצוגה המפורטת בהתאם למצב שבו הוא נמצא. לדוגמה,
יכול להיות שה-handler של הקליקים לא יבצע כל פעולה או שהוא יקפוץ חלון קופץ
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
בפריסה, התצוגה הבסיסית (root) תטופל
כתחום התמקדות מרומז. המשתמש לא יכול להזיז את המשתמש לנווט באפליקציה. במקום זאת,
להסתובב בין כל התצוגות הניתנות למיקוד, שעשויות להתאים לתיבות דו-שיח.
התאמה אישית של FocusArea
אפשר להשתמש בשני מאפיינים רגילים של תצוגה כדי להתאים אישית את החוגה של הניווט:
android:nextFocusForward
מאפשר למפתחי אפליקציות לציין את הסבב בסדר יורד. זה אותו מאפיין שמשמש לשליטה בסדר הכרטיסיות של ניווט באמצעות המקלדת. אין להשתמש במאפיין הזה כדי ליצור לולאה. במקום זאת, משתמשים ב-app:wrapAround
(ראו בהמשך) כדי ליצור לולאה.android:focusedByDefault
מאפשר למפתחי אפליקציות לציין תצוגת ברירת המחדל בחלון. לא להשתמש במאפיין הזה.app:defaultFocus
(ראו בהמשך) באותוFocusArea
.
FocusArea
גם מגדיר כמה מאפיינים להתאמה אישית של החוגה לניווט.
לא ניתן להתאים אישית אזורים מרומזים של התמקדות באמצעות המאפיינים האלה.
- (Android 11 QPR3, Android 11 Car,
Android 12)
אפשר להשתמש ב-app:defaultFocus
כדי לציין את המזהה של תצוגת צאצא שניתן להתמקד בה, שבה צריך להתמקד כשהמשתמש נדנודים אלFocusArea
הזה. - (Android 11 QPR3, Android 11 Car,
Android 12)
app:defaultFocusOverridesHistory
אפשר להגדיר ל-true
כדי שהתצוגה שצוינה למעלה תתמקד גם אם כדי לציין שצפייה אחרת בFocusArea
הזו התמקדה. - (Android 12)
שימוש ב-app:nudgeLeftShortcut
,app:nudgeRightShortcut
,app:nudgeUpShortcut
,app:nudgeDownShortcut
כדי לציין את המזהה של תצוגת צאצא שניתן להתמקד בה, שבו יש להתמקד כאשר שהמשתמש נדנוד בכיוון מסוים. למידע נוסף, אפשר לצפות בתוכן של נדנודים בהמשך.(Android 11 QPR3, Android 11 Car, הוצא משימוש ב-Android 12)
app:nudgeShortcut
ו-app:nudgeShortcutDirection
תומכים רק במקש קיצור אחד של נדנוד. - (Android 11 QPR3, Android 11 Car,
Android 12)
כדי להפעיל את הסיבוב כדי לנוע בתוךFocusArea
,app:wrapAround
יכול להיותtrue
. בדרך כלל משתמשים באפשרות הזו כשהתצוגות מסודרות לפי מעגל או אליפסה. - (Android 11 QPR3, Android 11 Car,
Android 12)
כדי לכוון את המרווח הפנימי של ההדגשהFocusArea
הזה, יש להשתמש ב-app:highlightPaddingStart
,app:highlightPaddingEnd
,app:highlightPaddingTop
,app:highlightPaddingBottom
,app:highlightPaddingHorizontal
, ו-app:highlightPaddingVertical
. - (Android 11 QPR3, Android 11 Car,
Android 12)
כדי לשנות את הגבולות הנתפסים שלFocusArea
כדי למצוא יעד נדנוד, להשתמש ב-app:startBoundOffset
,app:endBoundOffset
,app:topBoundOffset
,app:bottomBoundOffset
,app:horizontalBoundOffset
ו-app:verticalBoundOffset
. - (Android 11 QPR3, Android 11 Car,
Android 12)
כדי לציין במפורש את המזהה שלFocusArea
(או אזורים) סמוכים בכיוון הנתון, השתמשוapp:nudgeLeft
,app:nudgeRight
,app:nudgeUp
וגםapp:nudgeDown
. יש להשתמש באפשרות הזו כאשר החיפוש הגאומטרי המשמש כברירת מחדל לא מוצא את היעד הרצוי.
נדנוד בדרך כלל מנווט בין FocusAreas. אבל עם מקשי קיצור של נדנודים,
אם נדנודים, לפעמים הם מנווטים תחילה בתוך FocusArea
כך שהמשתמש עשוי להזדקק
כדי לדחות פעמיים כדי לנווט אל FocusArea
הבא. מקשי קיצור יכולים להיות שימושיים
כשFocusArea
מכיל רשימה ארוכה ואחריה
לחצן פעולה צף,
כמו בדוגמה הבאה:
בלי קיצור הדרך של הנדנוד, המשתמשים יצטרכו לסובב את כל הרשימה כדי להגיע FAB.
מיקוד ההתאמה האישית של ההדגשה
כפי שצוין למעלה, RotaryService
מתבסס על התפיסה הקיימת של Android Framework
להתמקד בתצוגה. כשהמשתמש מסובב ונדנוד את המשתמש, RotaryService
מזיז את המיקוד.
להתמקד בתצוגה אחת ולבטל התמקדות בתצוגה אחרת. ב-Android, כשמתמקדים בתצוגה, אם היא:
- מערכת 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 Car, Android 12) הפניות למשאבים מודגשות בדוגמה לזהות משאבים שמוגדרים על ידי ספריית המכונית לקרוא. ה-OEM (יצרן הציוד המקורי) מבטל את ההגדרות האלה כדי לשמור על עקביות באמצעות הדגשת המיקוד שהם מציינים כברירת מחדל. זה מבטיח שצבע ההדגשה של המוקד רוחב הקו, וכן הלאה לא ישתנו כשהמשתמשים עוברים בין תצוגה עם מיקוד מותאם אישית הדגשה ותצוגה עם הדגשת ברירת המחדל של המיקוד. הפריט האחרון הוא גלים שמשמשים למגע. ערכי ברירת המחדל המשמשים למשאבים המודגשים מופיעים כך:
כמו כן, מתבצעת קריאה להדגשה של מוקד מותאם אישית כאשר על הלחצן מוצג הדגשה קבועה כדי למשוך את תשומת הלב של המשתמש, כמו בדוגמה הבאה. הפעולה הזו יכולה להפוך את מודגשת המיקוד שקשה לראות. במצב כזה, תוכלו לציין הדגשת מיקוד מותאם אישית באמצעות צבעים משניים:
- (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
לדוגמה:
בפוקוס, לא לחוץ | התמקדות, לחיצה |
גלילה סיבובית
אם האפליקציה שלך משתמשת ב-RecyclerView
, צריך להשתמש בה
CarUiRecyclerView
במקום זאת. הדבר מבטיח שממשק המשתמש שלך תואם ל-
אחרים, כי ההתאמה האישית של ה-OEM חלה על כל ה-CarUiRecyclerView
.
אם ניתן להתמקד בכל הרכיבים ברשימה, אין צורך לבצע פעולה נוספת. ניווט סיבובי מעביר את המיקוד בין הרכיבים ברשימה ומתבצעת גלילה ברשימה כדי להציג את הרכיב החדש שבו מתמקדים.
(Android 11 QPR3, Android 11 Car,
Android 12)
אם יש שילוב של תכנים שניתנים למיקוד ולא ניתנים למיקוד
או אם לא ניתן להתמקד בכל הרכיבים, ניתן להפעיל גלילה סיבובית שמאפשרת
המשתמש יכול להשתמש בבקר החוגה כדי לגלול בהדרגה ברשימה בלי לדלג
פריטים שאי אפשר להתמקד בהם. כדי להפעיל גלילה סיבובית, צריך להגדיר app:rotaryScrollEnabled
ל-true
.
(Android 11 QPR3, Android 11 Car,
Android 12)
ניתן להפעיל גלילה סיבובית בכל
בתצוגה נגללת, כולל avCarUiRecyclerView
, עם
setRotaryScrollEnabled()
בCarUiUtils
. אם תעשו זאת,
צריך:
- אפשר להתמקד בתצוגה שניתנת לגלילה כדי שניתן יהיה להתמקד בה גם אם אף אחת ניתן להתמקד בתצוגת צאצאים,
- כדי להשבית את הדגשת ברירת המחדל של המיקוד בתצוגה הניתנת לגלילה על ידי התקשרות
setDefaultFocusHighlightEnabled(false)
כך שהתצוגה ניתנת לגלילה לא ממוקד. - כדי לוודא שתצוגת הגלילה מתמקדת לפני הצאצאים שלה, ניתן לבצע קריאה
setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS)
- מאזינים ל-MotionEvents עם
SOURCE_ROTARY_ENCODER
וגםAXIS_VSCROLL
אוAXIS_HSCROLL
כדי לציין את המרחק לגלילה ואת כיוון הנסיעה (דרך הסימן).
אם הגלילה החוגה מופעלת ב-CarUiRecyclerView
והמשתמש מסתובב
באזור שאין בו תצוגות שניתן להתמקד בהן, סרגל הגלילה משתנה מאפור לכחול, כאילו
כדי לציין שסרגל הגלילה ממוקד. אפשר ליישם אפקט דומה אם רוצים.
ה-MotionEvents זהים לאלו של האירועים שנוצרים על ידי גלגל גלילה על העכבר, מלבד המקור.
מצב מניפולציה ישירה
בדרך כלל, נדנודים וסיבובים מנווטים בממשק המשתמש, בזמן שהלחצן המרכזי לוחץ לנקוט פעולה, אם כי לא תמיד זה המצב. לדוגמה, אם משתמש רוצה לשנות את עוצמת הקול של ההתראה, ייתכן שהם ישתמשו בבקר החוגה כדי לנווט אל פס ההזזה של עוצמת הקול, לוחצים על הלחצן המרכזי, מסובבים את השלט רחוק כדי לכוונן את עוצמת הקול של ההתראה ולאחר מכן לוחצים על לחצן 'הקודם' כדי לחזור לניווט. מצב כזה נקרא מצב מניפולציה ישירה (DM). כאן בקר החוגה משמש לאינטראקציה ישירה עם התצוגה במקום לניווט.
אפשר להטמיע צ'אט באחת משתי דרכים. אם צריך רק לטפל בסיבוב ובתצוגה הרצויה
כדי להשפיע על תשובות לACTION_SCROLL_FORWARD
ACTION_SCROLL_BACKWARD
AccessibilityEvent
כמו שצריך, יש להשתמש ב
מנגנון פשוט. אחרת, יש להשתמש במנגנון המתקדם.
המנגנון הפשוט הוא האפשרות היחידה בחלונות המערכת. האפליקציות יכולות להשתמש בכל אחד מהמנגנונים.
מנגנון פשוט
(Android 11 QPR3, Android 11 Car,
Android 12)
האפליקציה צריכה להתקשר
DirectManipulationHelper.setSupportsRotateDirectly(View view, boolean enable)
התכונה RotaryService
מזהה כשהמשתמש נמצא במצב צ'אט ועובר למצב צ'אט כשהמשתמש
לוחץ על לחצן המרכז בזמן שהתצוגה מתמקדת. במצב צ'אט, הסיבובים מבצעים
ACTION_SCROLL_FORWARD
או ACTION_SCROLL_BACKWARD
ויציאה ממצב צ'אט
כשהמשתמש לוחץ על לחצן 'הקודם'. המנגנון הפשוט מחליף את המצב שנבחר
התצוגה בזמן הכניסה למצב צ'אט וביציאה ממנו.
כדי לסמן סימן ויזואלי שהמשתמש נמצא במצב צ'אט, אתם צריכים לשנות את התצוגה
כשנבחר. לדוגמה, אתם יכולים לשנות את הרקע
android:state_selected
היא true
.
מנגנון מתקדם
האפליקציה קובעת מתי RotaryService
נכנס למצב צ'אט ואיך יוצא ממנו. כדי לשמור על עקביות
חוויית משתמש, לחיצה על הלחצן המרכזי כשהתצוגה של הצ'אט מתמקדת אמורה להיכנס למצב צ'אט.
ולחצן 'הקודם' אמור לצאת ממצב צ'אט. אם לא משתמשים בלחצן המרכזי או בנדנוד,
הן יכולות להיות דרכים חלופיות ליציאה ממצב צ'אט. לאפליקציות כמו מפות Google, לחצן לייצוג
אפשר להשתמש בצ'אטים כדי להיכנס למצב צ'אט.
כדי לתמוך במצב צ'אט מתקדם:
- (Android 11 QPR3, Android 11 Car,
Android 12) חייבים להאזין ל-
KEYCODE_DPAD_CENTER
האירוע כדי להיכנס למצב צ'אט והאזנה לאירועKEYCODE_BACK
כדי לצאת ממצב צ'אט, קוראים לפונקציהDirectManipulationHelper.enableDirectManipulationMode()
בכל אחד מהמקרים. כדי להאזין לאירועים האלה, מבצעים אחת מהפעולות הבאות:- רישום
OnKeyListener
.
או,
- הרחבת התצוגה וביטול ה-method
dispatchKeyEvent()
של התצוגה.
- רישום
- צריכה להאזין לאירועי נדנודים (
KEYCODE_DPAD_UP
,KEYCODE_DPAD_DOWN
,KEYCODE_DPAD_LEFT
אוKEYCODE_DPAD_RIGHT
) אם התצוגה צריכה לטפל בנדנודים. - צריכה להאזין ל-
MotionEvent
ולקבל את מספר הסיבובים ב-AXIS_SCROLL
אם התצוגה רוצה לטפל בסבב. יש כמה דרכים לעשות זאת:- רישום
OnGenericMotionListener
. - הרחבת התצוגה וביטול ה-method
dispatchTouchEvent()
שלה.
- רישום
- כדי שלא תיתקע במצב צ'אט, חובה לצאת ממצב 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:
- אסור שניתן יהיה להתמקד ב
ActivityView
. - (Android 11 QPR3, Android 11 Car,
הוצא משימוש ב-Android 11)
התוכן שלActivityView
חייב להכילFocusParkingView
כתצוגה הראשונה שניתן להתמקד בה, וapp:shouldRestoreFocus
המאפיין חייב להיותfalse
. - התוכן של
ActivityView
לא יכול לכלולandroid:focusByDefault
צפיות.
עבור המשתמש, ל'תצוגות פעילות' לא תהיה כל השפעה על הניווט מלבד המיקוד הזה
אזורים לא יכולים להתפרס על 'תצוגות פעילות'. במילים אחרות, אין אפשרות להתמקד בתחום אחד
יש תוכן בתוך וגם מחוצה לו ActivityView
. אם לא תוסיפו
כל אזור FocusAres ב-ActivityView
, שהוא הרמה הבסיסית (root) של היררכיית התצוגות המפורטות ב-
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
מבצע פעולה (כמו הרצה אחורה) ומתזמן את עצמו
יופעלו לאחר עיכוב.
מצב מגע
המשתמשים יכולים להשתמש בבקר סיבובי כדי לקיים אינטראקציה עם היחידה הראשית (HU) ברכב בשתי דרכים: באמצעות השלט הרחוק של החוגה או על ידי נגיעה במסך. כשמשתמשים בבקר החוגה, אחת מהתצוגות הניתנות למיקוד מודגשת. כשנוגעים במסך, אין הדגשה של המיקוד מופיעה. המשתמשים יכולים לעבור בין שיטות הקלט האלה בכל שלב:
- סיבובי ← מגע. כשהמשתמש נוגע במסך, הדגשת המיקוד נעלמת.
- מקישים על ← חוגה. כשהמשתמש נדנד, מסובב או לוחץ על הלחצן 'מרכז', הדגשת המיקוד תופיע.
הלחצנים 'הקודם' ו'דף הבית' לא משפיעים על מצב הקלט.
תגים 'רוכבים' (piggybacking) מסתובבים על הקונספט הקיים של Android
מצב מגע.
אפשר להשתמש
View.isInTouchMode()
כדי לקבוע באיזה מצב קלט המשתמש משתמש. אפשר להשתמש
OnTouchModeChangeListener
כדי לזהות שינויים. אפשר להשתמש באפשרות הזו כדי להתאים אישית את ממשק המשתמש עבור
במצב קלט, להימנע משינויים משמעותיים מכיוון שהם עלולים להיות מטרידים.
פתרון בעיות
באפליקציה שמיועדת למגע, פעמים רבות יש תצוגות מקוננות שניתן להתמקד בהן.
לדוגמה, יכול להיות שיש FrameLayout
מסביב ל-ImageButton
,
ובשניהם ניתן להתמקד. פעולה זו לא פוגעת במגע, אבל יכולה לגרום
בחוויית המשתמש בחוגה כי המשתמש צריך לסובב את השלט רחוק פעמיים כדי לעבור
בתצוגה האינטראקטיבית הבאה. כדי לספק חוויית משתמש טובה, Google ממליצה
את התצוגה החיצונית או את התצוגה הפנימית, אבל לא את שתיהן.
אם לחצן או מתג מאבד את המיקוד כשלוחצים דרך החוגה דרך השלט הרחוק, אחת מהאפשרויות התנאים הבאים עשויים להתקיים:
- הלחצן או המתג מושבתים (לזמן קצר או ללא הגבלת זמן) עקב
שלוחצים על הלחצן. בכל מקרה, יש שתי דרכים לטפל בעניין:
- יש להשאיר את המצב
android:enabled
בתורtrue
ולהשתמש בהתאמה אישית כדי להציג את הלחצן או לעבור למצב אפור, כפי שמתואר מצב מותאם אישית. - צריך להשתמש במאגר כדי להקיף את הלחצן או את המתג ולהפוך את המאגר לניתן למיקוד במקום ללחוץ על הלחצן או על המתג. (ה-click listener חייב להיות בקונטיינר).
- יש להשאיר את המצב
- הלחצן או המתג מחליפים. לדוגמה, הפעולה שבוצעה כשהלחצן
נלחץ או שהמתג במצב מופעל, יכול להפעיל רענון של הפעולות הזמינות
ולגרום ללחצנים חדשים להחליף לחצנים קיימים. יש שתי דרכים לפתור את הבעיה:
- במקום ליצור לחצן או מתג חדש, הגדירו את הסמל או הטקסט של לחצן או מתג קיים.
- כפי שצוין למעלה, אפשר להוסיף מאגר שניתן להתמקד בו מסביב ללחצן או למתג הנגישות.
RotaryPlayground
RotaryPlayground
היא אפליקציית עזר לחוגה. בעזרת הכלי הזה אפשר ללמוד איך לשלב
בעזרת חוגה לאפליקציות. RotaryPlayground
כלול בגרסאות build של אמולטור וב-
מותאמות למכשירים עם מערכת ההפעלה Android Automotive OS (AAOS).
- מאגר של
RotaryPlayground
:packages/apps/Car/tests/RotaryPlayground/
- גרסאות: Android 11 QPR3, Android 11 Car, ו-Android 12
הכרטיסיות הבאות מוצגות באפליקציה RotaryPlayground
בצד ימין:
- כרטיסים. אפשר לנסות לנווט באזורי המיקוד ולדלג על רכיבים לא ממוקדים. וקלט טקסט.
- מניפולציה ישירה. בדיקת ווידג'טים שתומכים בתהליך פשוט ומתקדם במצב של מניפולציה ישירה. הכרטיסייה הזו מיועדת במיוחד למניפולציה ישירה בתוך חלון האפליקציה.
- מניפולציה של ממשק המשתמש של Sys. בדיקת ווידג'טים שתומכים במניפולציה ישירה בחלונות מערכת שבהם יש תמיכה רק במצב של מניפולציה ישירה פשוטה.
- רשת. ניתן לבדוק את הניווט החוגה של תבנית z באמצעות גלילה.
- התראה. אפשר לנסות נדנודים כדי להציג התראות 'שימו לב' ולצאת מהן.
- גוללים. מומלץ לבדוק את הגלילה בשילוב של רכיבים שניתן להתמקד בהם ושלא ניתן להתמקד בהם תוכן.
- WebView. מומלץ לבדוק את הניווט באמצעות קישורים ב-
WebView
. - בהתאמה אישית
FocusArea
. בדיקת ההתאמה האישית שלFocusArea
:- סיכום.
android:focusedByDefault
וגםapp:defaultFocus
.
- טירגוטים מפורשים של נדנודים.
- הסטה לקיצורי דרך.
FocusArea
ללא תצוגות שניתן להתמקד בהן.