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


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

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

مؤشر الانتقال للأعلى أو للأسفل

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

تتيح 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
        // ...
    }
}

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

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

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

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

class VolumeRange(
    val max: Int = 10,
    val min: Int = 0
)

private object VolumeViewModel {
    class MyViewModel : ViewModel() {
        private val _volumeState = mutableIntStateOf(0)
        val volumeState: State<Int>
            get() = _volumeState

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

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

val focusRequester: FocusRequester = remember { FocusRequester() }
val volumeViewModel: VolumeViewModel.MyViewModel =
    viewModel()
val volumeState by volumeViewModel.volumeState

TransformingLazyColumn(
    modifier = Modifier
        .fillMaxSize()
        .onRotaryScrollEvent {
            volumeViewModel.onVolumeChangeByScroll(it.verticalScrollPixels)
            true
        }
        .focusRequester(focusRequester)
        .focusable(),
) {
    // You can use volumeState here, for example:
    item {
        Text("Volume: $volumeState")
    }
}

يُرجى العِلم أنّه من أجل التبسيط، يستخدم المثال السابق قيم بكسل من المرجّح أن تكون حساسة للغاية إذا تم استخدامها فعليًا.