ورودی چرخشی با Compose

ورودی چرخشی به ورودی از قطعات ساعت شما که می چرخند یا می چرخند اشاره دارد. به طور متوسط، کاربران تنها چند ثانیه را صرف تعامل با ساعت خود می کنند. شما می توانید تجربه کاربری خود را با استفاده از ورودی روتاری افزایش دهید تا به کاربر اجازه دهید تا به سرعت وظایف مختلف را انجام دهد.

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

طومار

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

اسکرول چرخشی را با استفاده از Compose for Wear OS پیاده سازی کنید. این مثال یک برنامه را با یک داربست و یک ScalingLazyColumn توصیف می کند که به صورت عمودی پیمایش می کند. Scaffold ساختار طرح‌بندی اولیه را برای برنامه‌های Wear OS فراهم می‌کند و در حال حاضر یک شکاف برای نشانگر اسکرول دارد. برای نشان دادن پیشرفت پیمایش، یک نشانگر موقعیت بر اساس شی وضعیت لیست ایجاد کنید. نماهای قابل پیمایش، از جمله ScalingLazyColumn ، از قبل دارای حالت پیمایشی برای افزودن ورودی چرخشی هستند. برای دریافت رویدادهای اسکرول چرخشی، موارد زیر را انجام دهید:

  1. فوکوس را با استفاده از FocusRequester به صراحت درخواست کنید. از HierarchicalFocusCoordinator برای موارد پیچیده تر، مانند چندین شی ScalingLazyColumns در HorizontalPager استفاده کنید.

  2. اصلاح کننده onRotaryScrollEvent را برای رهگیری رویدادهایی که سیستم هنگام چرخاندن تاج یا چرخاندن قاب توسط کاربر ایجاد می کند، اضافه کنید. هر رویداد چرخشی دارای یک مقدار پیکسل تنظیم شده است و به صورت عمودی یا افقی پیمایش می کند. اصلاح کننده همچنین دارای یک تماس برگشتی است تا نشان دهد که آیا رویداد مصرف شده است یا خیر، و انتشار رویداد به والدین خود را هنگام مصرف متوقف می کند.

val listState = rememberScalingLazyListState()
Scaffold(
    positionIndicator = {
        PositionIndicator(scalingLazyListState = listState)
    }
) {

    val focusRequester = rememberActiveFocusRequester()
    val coroutineScope = rememberCoroutineScope()

    ScalingLazyColumn(
        modifier = Modifier
            .onRotaryScrollEvent {
                coroutineScope.launch {
                    listState.scrollBy(it.verticalScrollPixels)
                    listState.animateScrollBy(0f)
                }
                true
            }
            .focusRequester(focusRequester)
            .focusable()
            .fillMaxSize(),
        state = listState
    ) {
        // Content goes here
        // ...
    }
}

مقادیر گسسته

از فعل و انفعالات چرخشی برای تنظیم مقادیر گسسته نیز استفاده کنید، مانند تنظیم روشنایی در تنظیمات یا انتخاب اعداد در انتخابگر زمان هنگام تنظیم زنگ هشدار.

مشابه ScalingLazyColumn ، جمع کننده، لغزنده، استپر و سایر اجزای سازنده برای دریافت ورودی چرخشی باید فوکوس داشته باشند . در صورت وجود چندین هدف قابل پیمایش روی صفحه، مانند ساعت ها و دقیقه ها در انتخابگر زمان، برای هر هدف یک FocusRequester ایجاد کنید و زمانی که کاربر روی ساعت ها یا دقیقه ها ضربه می زند، تغییرات فوکوس را بر اساس آن مدیریت کنید.

var selectedColumn by remember { mutableIntStateOf(0) }

val hoursFocusRequester = remember { FocusRequester() }
val minutesRequester = remember { FocusRequester() }
// ...
Scaffold(modifier = Modifier.fillMaxSize()) {
    Row(
        // ...
        // ...
    ) {
        // ...
        Picker(
            readOnly = selectedColumn != 0,
            modifier = Modifier.size(64.dp, 100.dp)
                .onRotaryScrollEvent {
                    coroutineScope.launch {
                        hourState.scrollBy(it.verticalScrollPixels)
                    }
                    true
                }
                .focusRequester(hoursFocusRequester)
                .focusable(),
            onSelected = { selectedColumn = 0 },
            // ...
            // ...
        )
        // ...
        Picker(
            readOnly = selectedColumn != 1,
            modifier = Modifier.size(64.dp, 100.dp)
                .onRotaryScrollEvent {
                    coroutineScope.launch {
                        minuteState.scrollBy(it.verticalScrollPixels)
                    }
                    true
                }
                .focusRequester(minutesRequester)
                .focusable(),
            onSelected = { selectedColumn = 1 },
            // ...
            // ...
        )
        LaunchedEffect(selectedColumn) {
            listOf(
                hoursFocusRequester,
                minutesRequester
            )[selectedColumn]
                .requestFocus()
        }
    }
}

اقدامات سفارشی

همچنین می توانید اقدامات سفارشی را ایجاد کنید که به ورودی چرخشی در برنامه خود پاسخ می دهند. برای مثال، از ورودی چرخشی برای بزرگ‌نمایی و کوچک‌نمایی یا کنترل صدا در یک برنامه رسانه استفاده کنید.

اگر مؤلفه شما به طور بومی از رویدادهای پیمایش مانند کنترل صدا پشتیبانی نمی کند، می توانید رویدادهای اسکرول را خودتان مدیریت کنید.

// VolumeScreen.kt

val focusRequester: FocusRequester = remember { FocusRequester() }

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

یک حالت سفارشی مدیریت شده در مدل view ایجاد کنید و یک فراخوان سفارشی که برای پردازش رویدادهای اسکرول چرخشی استفاده می شود.

// 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(),
) { ... }

منابع اضافی

استفاده از Horologist، یک پروژه منبع باز Google را در نظر بگیرید که مجموعه‌ای از کتابخانه‌های Wear را ارائه می‌کند که عملکرد ارائه‌شده توسط Compose برای Wear OS و دیگر APIهای Wear OS را تکمیل می‌کند. Horologist پیاده سازی را برای موارد استفاده پیشرفته و بسیاری از جزئیات خاص دستگاه ارائه می دهد.

به عنوان مثال، حساسیت منابع ورودی چرخشی مختلف می تواند متفاوت باشد. برای انتقال روان‌تر بین مقادیر، می‌توانید محدودیت را رتبه‌بندی کنید یا عکس‌های متحرک یا انیمیشن‌ها را برای انتقال اضافه کنید. این اجازه می دهد تا سرعت چرخش برای کاربران طبیعی تر باشد. Horologist شامل اصلاح کننده هایی برای اجزای قابل پیمایش و مقادیر گسسته است. همچنین شامل ابزارهای کاربردی برای کنترل فوکوس و یک کتابخانه رابط کاربری صوتی برای اجرای کنترل صدا با لمسی است.

برای اطلاعات بیشتر، به Horologist در GitHub مراجعه کنید.

{% کلمه به کلمه %} {% آخر کلمه %} {% کلمه به کلمه %} {% آخر کلمه %}