החל מ-Wear OS 7 (רמת API 37), מסגרת של מחוות ביד אחת, יחד עם API שהוא חלק מ-Compose ל-Wear OS, מאפשרת למשתמשים ליצור אינטראקציה עם האפליקציה בלי לגעת במסך.
המסגרת נתמכה בהתחלה במכשירי Pixel Watch (Pixel Watch 3 ואילך), אבל היא זמינה לכל יצרני הציוד המקורי. אם תטמיעו את ה-API הזה, התמיכה במחוות באפליקציה שלכם תתרחב אוטומטית בכל האקוסיסטם ככל שהתמיכה בחומרה תתרחב.
כדי לעזור למשתמשים לגלות את המחוות הזמינות בלי להעמיס על ממשק המשתמש, מסגרת Wear OS מספקת אינדיקטורים של מחוות מונפשות. הרמזים החזותיים האלה מדגישים איפה אפשר לבצע תנועה, והמערכת מנהלת באופן אוטומטי את קצב ההצגה ואת תדירות ההשתקה שלהם בהתאם להעדפות המשתמש.
פעולות ותנועות נתמכות
Framework המחוות של Wear OS תומך בשני סוגים של מחוות:
- פעולה ראשית (צביטה כפולה): ממופה לפעולה הראשית במסך, כמו מענה לשיחה או הפעלה/הפסקה של הפעלת מדיה.
- ביטול פעולה (סיבוב פרק כף היד): ממופה לניווט אחורה, לביטול תיבת דו-שיח או לביטול הנחיה.
הגדרת תנועות ב-Compose
ממשק ה-API של מחוות ביד אחת יכול לשפר את ממשק המשתמש, אבל חשוב לזכור שיש חומרה ויצרני ציוד מקורי שלא תומכים במחוות האלה. אם ה-API מזהה שהאפליקציה פועלת באחד מהמכשירים הלא נתמכים האלה, הספרייה לא מבצעת פעולה באופן אוטומטי, בלי להשפיע על אינטראקציות רגילות של מגע.
בדומה להתנהגויות הרגילות של Compose, אפשר להפעיל מחוות ביד אחת ברכיבי ממשק המשתמש באמצעות modifiers. אתם מגדירים את מחוות האפליקציה בהתאם לפעולה שרוצים לבצע – ראשונית או ביטול – וgestureIdכדי לתאם עם העדפות המשתמש ברמת המערכת, כמו קצב הצגת הרמזים והשתקת התדירות. כדי להגדיר את ההגדרה הזו, צריך ליצור אובייקט OneHandedGestureConfiguration. מומלץ להשתמש בפונקציה rememberOneHandedGestureConfiguration כדי ליצור אותו. ב-OneHandedGestureConfiguration אפשר גם לציין את העדיפות של תנועת היד.
הפונקציה rememberOneHandedGestureConfiguration עוקבת אחרי היסטוריית האינטראקציות של המשתמשים במהלך הרכבות מחדש, בלי לחשוף את מצב האפליקציה. אחרי שהאפליקציה יוצרת את ההגדרה, היא צריכה להעביר אותה אל Modifier.oneHandedGesture ברכיב הניתן להרכבה האינטראקטיבי.
כדי לעזור למשתמשים לגלות את התנועות הזמינות, הספרייה מספקת את השיטה OneHandedGestureClickIndicator. השיטה הזו פועלת כעטיפה שמחליפה את התוכן הבסיסי שלה כדי לציין למשתמש שפעולת תנועה זמינה.
רכיבים אינטראקטיביים
כדי להפעיל תנועות ידיים ואצבעות ברכיב אינטראקטיבי כמו לחצן, צריך ליצור הגדרה שבה מצוין OneHandedGestureAction.Primary ולהחיל את המשנה oneHandedGesture. מעבירים את אותו MutableInteractionSource גם לרכיב הבקרה וגם לרכיב השינוי, כדי שאירועי מחוות יפיקו משוב חזותי של לחיצה על רכיב הבקרה.
כדי להפעיל את אינדיקטור התנועות, יוצרים מופע של
OneHandedGestureClickIndicatorState וזוכרים אותו. לאחר מכן, כדי להפעיל את המשוב החזותי, צריך להתקשר אל showIndicator בתוך הקריאה החוזרת onGestureAvailable שסופקה על ידי משנה oneHandedGesture, שמאותת למערכת שקרה אירוע של אינדיקציה. אחרי הקריאה, הרכיב מחליף לזמן קצר את התוכן הרגיל שלו באנימציה של תנועת יד.
var isPlaying by remember { mutableStateOf(false) } val onClick = { isPlaying = !isPlaying } val gestureConfig = rememberOneHandedGestureConfiguration( action = OneHandedGestureAction.Primary ) val indicatorState = remember { OneHandedGestureClickIndicatorState() } val coroutineScope = rememberCoroutineScope() val interactionSource = remember { MutableInteractionSource() } Button( onClick = onClick, interactionSource = interactionSource, modifier = Modifier .fillMaxWidth() .oneHandedGesture( gestureConfiguration = gestureConfig, interactionSource = interactionSource, onGestureLabel = if (isPlaying) "pause" else "play", onGestureAvailable = { coroutineScope.launch { indicatorState.showIndicator() } }, onGesture = onClick ) ) { OneHandedGestureClickIndicator( gestureConfiguration = gestureConfig, state = indicatorState ) { Text(if (isPlaying) "Pause" else "Play", modifier = Modifier.fillMaxWidth()) } }
מאגרים עם אפשרות גלילה
במסכים או ברשימות שאפשר לגלול בהם, יוצרים הגדרה שמציינת OneHandedGestureAction.Primary ומחילים את משנה המאפיין oneHandedGesture על הקונטיינר, ומפעילים פונקציית עזר לגלילה כמו scrollDown.
כדי לספק משוב חזותי לפעולות גלילה, אפשר להשתמש ב-OneHandedGestureScrollIndicator. הרכיב הזה פועל כמחוון גלילה רגיל שמציג את מיקום הגלילה, אבל הוא יכול גם לציין שיש למשתמש אפשרות לבצע תנועת גלילה. האינדיקטור הזה מועבר בדרך כלל למקום scrollIndicator של ScreenScaffold, והוא משולב עם הסטטוס של קונטיינר עם אפשרות גלילה, כמו TransformingLazyColumn. הוא גם מתבסס על OneHandedGestureScrollIndicatorState כדי לנהל את המעברים החזותיים.
כדי להפעיל את המשוב החזותי, קוראים ל-showIndicator במצב הזה – בדרך כלל בתוך הקריאה החוזרת (callback) של onGestureAvailable של שינוי oneHandedGesture.
אחרי ההפעלה, האינדיקטור מחליף באופן זמני את המצב החזותי הרגיל שלו ברצף של אנימציות של תנועות, כדי להתריע בפני המשתמש.
val scrollState = rememberTransformingLazyColumnState() val gestureConfig = rememberOneHandedGestureConfiguration( action = OneHandedGestureAction.Primary, priority = OneHandedGesturePriority.Scrollable ) val indicatorState = remember(gestureConfig) { OneHandedGestureScrollIndicatorState() } val coroutineScope = rememberCoroutineScope() ScreenScaffold( scrollState = scrollState, scrollIndicator = { OneHandedGestureScrollIndicator( gestureConfiguration = gestureConfig, indicatorState = indicatorState, scrollState = scrollState, modifier = Modifier.align(Alignment.CenterEnd) ) } ) { contentPadding -> TransformingLazyColumn( state = scrollState, contentPadding = contentPadding, modifier = Modifier .fillMaxSize() .oneHandedGesture( gestureConfiguration = gestureConfig, onGestureLabel = "scroll", onGestureAvailable = { coroutineScope.launch { indicatorState.showIndicator() } }, onGesture = { OneHandedGestureDefaults.scrollDown(scrollState) } ) ) { items(10) { index -> Text("Item $index", modifier = Modifier.padding(8.dp)) } } }
שילוב של כמה תנועות
אפשר להגדיר גם תנועת גלילה וגם תנועת לחיצה עם אותה פעולה ראשית על ידי הוספת gesturePriority לאובייקט OneHandedGestureConfiguration:
-
OneHandedGesturePriority.Clickable(הכי גבוה): הקצאה לפקדים אינטראקטיביים – כמו אלה עם הסוגButtonאוCard– כדי שהם יתעדו תנועות כשרואים אותם במסך. -
OneHandedGesturePriority.Scrollable(בינוני): הגדרה זו מיועדת למאגרי תצוגה שניתן לגלול או להעביר בהם דפים, כדי שהם יתאימו לצאצאים שניתן ללחוץ עליהם, אבל יגללו כשלא מוצג פקד שאפשר ללחוץ עליו. -
OneHandedGesturePriority.Unspecified(הנמוכה ביותר): עדיפות שלא הוקצתה. זהו ערך ברירת המחדל עבור תנועה שלא הוגדר להpriority.
אם מגדירים באופן מפורש את priority = OneHandedGesturePriority.Clickable
בלחצן פנימי ואת priority = OneHandedGesturePriority.Scrollable
ברשימת ההורה שלו, המערכת יכולה להציג את ההתנהגות הזו של עדיפות למחוות.
כשהמשתמש מפעיל את הפעולה הראשית באמצעות תנועת יד אחת, המערכת קודם גוללת את הרשימה למטה עד שהלחצן נראה. לאחר מכן, המערכת מתעדת את פעולת הלחיצה על הלחצן.
בדיקה וניפוי באגים של תנועות באמצעות ADB
אפשר לבדוק את התנועות ביד אחת במכשיר פיזי או באמולטור בלי לבצע תנועות פיזיות של פרק כף היד, באמצעות Android Debug Bridge (adb) ושירות המערכת IWearGestureService.
הפעלת סימולציית תנועות
- מוודאים שבמכשיר Wear OS פועלת מערכת Wear OS 7 (רמת API 37) ומעלה.
- אם בודקים במכשיר פיזי שלא נמצא על פרק כף היד או במטען, צריך לבטל את ההגדרה של מצב החיישן כשהמכשיר לא על הגוף כדי שהמכשיר יישאר פעיל:
adb shell cmd sensorservice set-off-body-state 0
הפעלת אירועים של תנועות באמצעות ADB
כדי לדמות את התנועה הצמדת אצבעות פעמיים (שהיא הפעולה Primary בשעוני Pixel), מריצים את פקודת ה-ADB shell הבאה:
adb shell cmd IWearGestureService gesture 1
כדי לדמות את תנועת סיבוב פרק כף היד (שהיא הפעולה Dismiss בשעוני Pixel), מריצים את פקודת ה-ADB shell הבאה:
adb shell cmd IWearGestureService gesture 2
איפוס המעקב אחר רמזים לתנועות
המערכת עוקבת אחרי היסטוריית האינטראקציות של המשתמש ומציגה רמזים לגבי תנועות צפות על סמך הגדרת הקצב הגלובלית (למשל תמיד או יומי). כשמבצעים ניפוי באגים במחווני התנועות של האפליקציה, צריך לאפס את היסטוריית המעקב הזו כדי שההצעות יופיעו שוב לחבילה:
adb shell cmd IWearGestureService hint clear <your_package_name>
כדי לאפס את הסטטוס של החיישן לזיהוי המכשיר כשהוא לא על הגוף אחרי שמסיימים את הבדיקה:
adb shell cmd sensorservice reset-off-body-state
מקורות מידע נוספים
במאמר תנועות ביד אחת מוסבר מתי ואיפה כדאי להשתמש בתנועות ביד אחת.
מומלץ בשבילך
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- מדריך לעיצוב תנועות של יד אחת