إدخال البيانات عبر وحدة تحكُّم دورانية باستخدام Compose


يشير الإدخال عبر وحدة تحكّم دورانية إلى إدخال البيانات من أجزاء الساعة التي تدور أو تتحرّك بشكل دائري. في المتوسط، لا يستغرق تفاعل المستخدمين مع ساعاتهم سوى بضع ثوانٍ. يمكنك تحسين تجربة المستخدم من خلال استخدام ميزة "الإدخال الدوّار" للسماح للمستخدم بإنجاز مهام مختلفة بسرعة.

تشمل المصادر الرئيسية الثلاثة للإدخال الدوّار في معظم الساعات الزر الجانبي الدوّار، وإما إطارًا دوّارًا ماديًا أو إطارًا دوّارًا يعمل باللمس، وهو عبارة عن منطقة لمس دائرية حول الشاشة. على الرغم من أنّ السلوك المتوقّع قد يختلف استنادًا إلى نوع الإدخال، احرص على توفير إمكانية الإدخال باستخدام زر التدوير لجميع التفاعلات الأساسية.

صفحة مواضع التمرير

يتوقّع معظم المستخدمين أن تتيح التطبيقات إمكانية التمرير. أثناء تمرير المحتوى على الشاشة، قدِّم للمستخدمين ملاحظات مرئية استجابةً للتفاعلات باستخدام أداة التحكم الدوّارة. يمكن أن تتضمّن الملاحظات المرئية مؤشرات التمرير للتمرير عموديًا أو مؤشرات الصفحات.

تتيح ScalingLazyColumn وTransformingLazyColumn وPicker إيماءة التمرير تلقائيًا، طالما أنّك بحاجة إلى وضع هذه المكوّنات داخل AppScaffold وScreenScaffold وتمرير حالة القائمة بين ScreenScaffold والمكوّن، مثل TransformingLazyColumn.

يوفر AppScaffold وScreenScaffold بنية التنسيق الأساسية لتطبيقات Wear OS ويتضمّن بالفعل موضعًا لمؤشر التمرير مع تنفيذ تلقائي. لتخصيص مستوى تقدّم التمرير، أنشئ مؤشر تمرير استنادًا إلى عنصر حالة القائمة، كما هو موضّح في مقتطف الرمز البرمجي التالي:

val listState = rememberTransformingLazyColumnState()
ScreenScaffold(
    scrollState = listState,
    scrollIndicator = {
        ScrollIndicator(state = listState)
    }
) {
    // ...
}

يمكنك ضبط سلوك المحاذاة لـ ScalingLazyColumn باستخدام ScalingLazyColumnDefaults.snapFlingBehavior، كما هو موضّح في مقتطف الرمز التالي:

val listState = rememberScalingLazyListState()
ScreenScaffold(
    scrollState = listState,
    scrollIndicator = {
        ScrollIndicator(state = listState)
    }
) {

    val state = rememberScalingLazyListState()
    ScalingLazyColumn(
        modifier = Modifier.fillMaxWidth(),
        state = state,
        flingBehavior = ScalingLazyColumnDefaults.snapFlingBehavior(state = state)
    ) {
        // Content goes here
        // ...
    }
}

الإجراءات المخصّصة

يمكنك أيضًا إنشاء إجراءات مخصّصة تستجيب للإدخال عبر وحدة تحكّم دورانية في تطبيقك. على سبيل المثال، يمكنك استخدام الإدخال عبر وحدة تحكّم دورانية للتكبير والتصغير أو للتحكّم في مستوى الصوت في تطبيق وسائط.

إذا كان المكوّن لا يتيح بشكلٍ تلقائي أحداث التمرير، مثل التحكّم في مستوى الصوت، يمكنك معالجة أحداث التمرير بنفسك.

// VolumeScreen.kt

val focusRequester: FocusRequester = remember { FocusRequester() }

Column(
    modifier = Modifier
        .fillMaxSize()
        .onRotaryScrollEvent {
            // handle rotary scroll events
            true
        }
        .focusRequester(focusRequester)
        .focusable(),
) { ... }

أنشئ حالة مخصّصة تتم إدارتها في نموذج العرض، ودالة ردّ نداء مخصّصة تُستخدَم لمعالجة أحداث التمرير الدائري.

// VolumeViewModel.kt

object VolumeRange(
    public val max: Int = 10
    public val min: Int = 0
)

val volumeState: MutableStateFlow<Int> = ...

fun onVolumeChangeByScroll(pixels: Float) {
    volumeState.value = when {
        pixels > 0 -> min (volumeState.value + 1, VolumeRange.max)
        pixels < 0 -> max (volumeState.value - 1, VolumeRange.min)
    }
}

لتبسيط الأمر، يستخدم المثال السابق قيم وحدات بكسل من المحتمل أن تكون حساسة بشكل مفرط إذا تم استخدامها فعليًا.

استخدِم دالة معاودة الاتصال بعد تلقّي الأحداث، كما هو موضّح في المقتطف التالي.

val focusRequester: FocusRequester = remember { FocusRequester() }
val volumeState by volumeViewModel.volumeState.collectAsState()

Column(
    modifier = Modifier
        .fillMaxSize()
        .onRotaryScrollEvent {
            volumeViewModel
                .onVolumeChangeByScroll(it.verticalScrollPixels)
            true
        }
        .focusRequester(focusRequester)
        .focusable(),
) { ... }