حرکات یک دستی با Compose


در Wear OS 7 (سطح API 37) و بالاتر، یک چارچوب ژست‌های حرکتی یک دستی، به همراه یک API که بخشی از Compose for Wear OS است، به کاربران اجازه می‌دهد بدون لمس با برنامه شما تعامل داشته باشند.

اگرچه این چارچوب در ابتدا در دستگاه‌های پیکسل واچ (پیکسل واچ ۳ و بالاتر) پشتیبانی می‌شد، اما اکنون برای همه تولیدکنندگان اصلی تجهیزات (OEM) در دسترس است. با اتخاذ این API، پشتیبانی از ژست‌های حرکتی برنامه شما با گسترش پشتیبانی سخت‌افزاری، به طور خودکار در سراسر اکوسیستم مقیاس‌پذیر می‌شود.

برای کمک به کاربران در کشف حرکات موجود بدون شلوغ کردن رابط کاربری، چارچوب Wear OS نشانگرهای حرکتی متحرک را ارائه می‌دهد. این نکات بصری محل انجام یک حرکت را برجسته می‌کنند، در حالی که سیستم به طور خودکار آهنگ نمایش و فرکانس بی‌صدا کردن آنها را مطابق با ترجیحات کاربر مدیریت می‌کند.

حرکات و اقدامات پشتیبانی شده

چارچوب حرکات Wear OS از دو نوع حرکت پشتیبانی می‌کند:

  • اقدام اصلی (دو بار نیشگون گرفتن): به اقدام اصلی روی صفحه نمایش، مانند پاسخ دادن به تماس یا تغییر وضعیت پخش رسانه، اشاره می‌کند.
  • لغو اقدام (چرخاندن مچ): به پیمایش رو به عقب، رد کردن یک کادر محاوره‌ای یا لغو یک درخواست اشاره دارد.

پیکربندی حرکات در نوشتن

اگرچه API حرکات یک دستی می‌تواند رابط کاربری شما را بهبود بخشد، اما باید در نظر داشته باشید که برخی از سخت‌افزارها و تولیدکنندگان اصلی تجهیزات (OEM) از این حرکات پشتیبانی نمی‌کنند. اگر API تشخیص دهد که برنامه شما روی یکی از این دستگاه‌های پشتیبانی نشده اجرا می‌شود، کتابخانه به طور خودکار بدون تأثیر بر تعاملات لمسی استاندارد، عملیات را متوقف می‌کند.

همانند رفتارهای استاندارد نوشتن، شما با استفاده از اصلاح‌کننده‌ها ، حرکات تک‌دستی را روی عناصر رابط کاربری فعال می‌کنید. حرکات برنامه خود را بر اساس عملی که باید انجام شود - یا اصلی یا رد کردن - و یک gestureId برای هماهنگی با تنظیمات کاربر در سطح سیستم، مانند آهنگ نمایش اشاره و بی‌صدا کردن فرکانس، پیکربندی می‌کنید. شما این پیکربندی را با ایجاد یک شیء OneHandedGestureConfiguration بیان می‌کنید. توصیه می‌کنیم از تابع rememberOneHandedGestureConfiguration برای ایجاد آن استفاده کنید. OneHandedGestureConfiguration همچنین جایی است که می‌توانید اولویت حرکات را ارائه دهید.

تابع rememberOneHandedGestureConfiguration تاریخچه تعامل کاربر را در طول recompositionها بدون افشای وضعیت برنامه، ردیابی می‌کند. هنگامی که برنامه شما پیکربندی را ایجاد کرد، باید پیکربندی را به Modifier.oneHandedGesture در interactive composable شما منتقل کند.

برای کمک به کاربران در کشف حرکات موجود، این کتابخانه متد 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 فراخوانی کنید - که معمولاً درون تابع 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 آزمایش کنید.

فعال کردن شبیه‌سازی ژست

قبل از شبیه‌سازی حرکات با استفاده از ADB، تنظیمات دستگاه و لغو محدودیت‌ها را پیکربندی کنید:

  1. تأیید کنید که دستگاه Wear OS شما از Wear OS 7 (سطح API 37) و بالاتر استفاده می‌کند:

    adb shell getprop ro.build.version.sdk
    
  2. اگر روی یک دستگاه فیزیکی که روی مچ دست شما نیست یا به شارژر متصل است، آزمایش می‌کنید، محدودیت خارج از بدن را لغو کنید تا چارچوب ژست فعال بماند:

    adb shell cmd IWearGestureService override-constraints offbody-state
    

فعال کردن رویدادهای حرکتی با استفاده از ADB

برای شبیه‌سازی ژست دو انگشتی (که عملکرد Primary در ساعت‌های پیکسل است)، دستور زیر را در پوسته ADB اجرا کنید:

adb shell cmd IWearGestureService gesture DoublePinch

برای شبیه‌سازی حرکت چرخش مچ (که در ساعت‌های پیکسل، عمل Dismiss است)، دستور ADB shell زیر را اجرا کنید:

adb shell cmd IWearGestureService gesture WristTurn

تنظیم مجدد ردیابی اشاره حرکتی

سیستم تاریخچه تعامل کاربر را ردیابی می‌کند و بر اساس تنظیمات کلی (مانند Always یا Daily ) نکات حرکتی شناور را نمایش می‌دهد. هنگام اشکال‌زدایی نشانگرهای حرکتی برنامه خود، این تاریخچه ردیابی را مجدداً تنظیم کنید تا نکات برای بسته شما دوباره ظاهر شوند:

  • در نسخه‌های ساخته‌شده userdebug یا شبیه‌سازها:

    adb shell cmd IWearGestureService hint clear <your_package_name>
    
  • در نسخه‌های خرده‌فروشی ( user ):

    در دستگاه‌های تجاری بدون دسترسی روت، hint clear توسط مجوزهای سیستم مسدود شده است. برای تنظیم مجدد قابلیت Hint Discovery، داده‌های محلی برنامه را پاک کنید:

    adb shell pm clear <your_package_name>
    

بازگرداندن محدودیت‌های پیش‌فرض

برای تنظیم مجدد همه لغو محدودیت‌های اشکال‌زدایی پس از پایان آزمایش:

adb shell cmd IWearGestureService override-constraints reset

عیب‌یابی تزریق ژست

اگر برنامه شما حرکات شبیه‌سازی‌شده را دریافت نمی‌کند:

  1. تأیید کنید که صفحه ساعت بیدار و روشن است. چارچوب ژست‌های حرکتی، در حالی که صفحه خاموش است یا در حالت محیطی قرار دارد، ژست‌ها را به برنامه‌ها ارسال نمی‌کند. برای بیدار کردن صفحه نمایش با استفاده از ADB، دستور زیر را اجرا کنید:

    adb shell input keyevent KEYCODE_WAKEUP
    
  2. بررسی کنید که آیا برنامه شما به عنوان یک مشترک ژست فعال ثبت شده است و در حال حاضر فوکوس پنجره را نگه داشته است یا خیر:

    adb shell cmd IWearGestureService get-active-gestures -readable
    

    وقتی صفحه ژست برنامه شما در پیش‌زمینه است و صفحه نمایش فعال است، این دستور [DoublePinch] یا [DoublePinch, WristTurn] را برمی‌گرداند. اگر یک لیست خالی ( [] ) برگردانده شود، بررسی کنید که آیا پنجره شما فوکوس دارد یا محدودیت‌های خارج از بدنه مانع فعال‌سازی می‌شوند.

  3. وضعیت سرویس ژست‌های داخلی و توکن‌های فعال مشترکین را بررسی کنید:

    adb shell dumpsys IWearGestureService
    

منابع اضافی

برای راهنمایی طراحی در مورد زمان و مکان استفاده از حرکات یک دستی، به حرکات یک دستی مراجعه کنید.

{% کلمه به کلمه %} {% فعل کمکی %} {% کلمه به کلمه %} {% فعل کمکی %}