تغییردهنده‌های پیمایش

اصلاح‌کننده‌های verticalScroll و horizontalScroll ساده‌ترین روش را برای اینکه کاربر بتواند در عنصر پیمایش کند ارائه می‌دهند، وقتی که حدود محتوای آن بزرگ‌تر از محدودیت‌های حداکثر اندازه آن باشد. با اصلاح‌کننده‌های verticalScroll و horizontalScroll نیازی به ترجمه یا جابه‌جایی محتوا ندارید.

@Composable
private fun ScrollBoxes() {
    Column(
        modifier = Modifier
            .background(Color.LightGray)
            .size(100.dp)
            .verticalScroll(rememberScrollState())
    ) {
        repeat(10) {
            Text("Item $it", modifier = Modifier.padding(2.dp))
        }
    }
}

فهرست عمودی ساده‌ای که به اشاره‌های پیمایش پاسخ می‌دهد
شکل ۱. فهرست عمودی ساده‌ای که به اشاره‌های پیمایش پاسخ می‌دهد.

ScrollState به شما امکان می‌دهد موقعیت پیمایش را تغییر دهید یا وضعیت فعلی آن را دریافت کنید. برای ایجاد آن با پارامترهای پیش‌فرض، از rememberScrollState() استفاده کنید.

@Composable
private fun ScrollBoxesSmooth() {
    // Smoothly scroll 100px on first composition
    val state = rememberScrollState()
    LaunchedEffect(Unit) { state.animateScrollTo(100) }

    Column(
        modifier = Modifier
            .background(Color.LightGray)
            .size(100.dp)
            .padding(horizontal = 8.dp)
            .verticalScroll(state)
    ) {
        repeat(10) {
            Text("Item $it", modifier = Modifier.padding(2.dp))
        }
    }
}

اصلاح‌گر ناحیه پیمایش‌پذیر

اصلاح‌کننده scrollableArea یک واحد سازنده اساسی برای ایجاد محفظه‌های پیمایشی سفارشی است. این مؤلفه انتزاعی سطح بالاتری نسبت‌به اصلاح‌کننده scrollable ارائه می‌دهد و الزامات رایجی مانند تفسیر دلتای اشاره، برش محتوا، و جلوه‌های پیمایش بیش‌ازحد را مدیریت می‌کند.

درحالی‌که از scrollableArea برای پیاده‌سازی‌های سفارشی استفاده می‌شود، به‌طور کلی باید راه‌حل‌های آماده مانند verticalScroll، horizontalScroll، یا ترکیب‌پذیرهایی مانند LazyColumn را برای فهرست‌های پیمایشی استاندارد ترجیح دهید. این مؤلفه‌های سطح بالاتر برای موارد استفاده رایج ساده‌تر هستند و خودشان بااستفاده از scrollableArea ساخته شده‌اند.

تفاوت بین اصلاح‌کننده‌های scrollableArea و scrollable

تفاوت اصلی بین scrollableArea و scrollable در نحوه تفسیر اشاره‌های پیمایش کاربر است:

  • scrollable (دلتا خام): دلتا مستقیماً منعکس‌کننده حرکت فیزیکی ورودی کاربر (مثلاً کشیدن اشاره‌گر) روی صفحه است.
  • scrollableArea (تغییر محتواگرا): delta ازنظر معنایی معکوس می‌شود تا تغییر انتخاب‌شده در موقعیت پیمایش را نشان دهد تا به‌نظر برسد محتوا با اشاره کاربر حرکت می‌کند، که معمولاً مخالف حرکت اشاره‌گر است.

این‌طور به آن فکر کنید: scrollable به شما می‌گوید که اشاره‌گر چگونه حرکت کرده است، درحالی‌که scrollableArea آن حرکت اشاره‌گر را به نحوه حرکت محتوا در یک نمای پیمایشی معمولی ترجمه می‌کند. این وارونگی دلیل این است که چرا scrollableArea هنگام پیاده‌سازی محفظه پیمایشی استاندارد طبیعی‌تر به‌نظر می‌رسد.

جدول زیر علامت‌های دلتا را برای سناریوهای رایج خلاصه می‌کند:

اشاره کاربر

دلتا گزارش‌شده به dispatchRawDelta توسط scrollable

دلتا گزارش‌شده به dispatchRawDelta توسط scrollableArea*

اشاره‌گر به بالا حرکت می‌کند

منفی

مثبت

اشاره‌گر به پایین حرکت می‌کند

مثبت

منفی

اشاره‌گر به چپ حرکت می‌کند

منفی

مثبت (منفی برای راست‌به‌چپ)

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

مثبت

منفی (مثبت برای راست به چپ)

(*) نکته‌ای درباره علامت دلتا scrollableArea: علامت دلتا از scrollableArea فقط یک وارونگی ساده نیست. این ویژگی به‌طور هوشمندانه موارد زیر را درنظر می‌گیرد:

  1. جهت: عمودی یا افقی.
  2. LayoutDirection: چپ به راست یا راست به چپ (به‌ویژه برای پیمایش افقی مهم است).
  3. پرچم reverseScrolling: آیا جهت پیمایش معکوس شده است.

علاوه‌بر معکوس کردن دلتای پیمایش، scrollableArea محتوا را به مرزهای چیدمان برش می‌دهد و رندر کردن جلوه‌های پیمایش بیش‌ازحد را مدیریت می‌کند. به‌طور پیش‌فرض، از جلوه ارائه‌شده توسط LocalOverscrollFactory استفاده می‌کند. می‌توانید این مورد را بااستفاده از سربارگذاری scrollableArea که پارامتر OverscrollEffect را می‌پذیرد سفارشی‌سازی یا غیرفعال کنید.

زمان استفاده از اصلاح‌کننده scrollableArea

وقتی می‌خواهید مؤلفه پیمایش سفارشی بسازید که اصلاح‌کننده‌های horizontalScroll یا verticalScroll یا طرح‌بندی‌های Lazy به‌اندازه کافی آن را پوشش نمی‌دهند، باید از اصلاح‌کننده scrollableArea استفاده کنید. این موارد اغلب شامل پرونده‌هایی با این ویژگی‌ها است:

  • منطق چیدمان سفارشی: وقتی ترتیب موارد به‌طور پویا براساس موقعیت پیمایش تغییر می‌کند.
  • جلوه‌های دیداری منحصربه‌فرد: اعمال تبدیل، مقیاس‌بندی، یا جلوه‌های دیگر به فرزندان هنگام پیمایش.
  • کنترل مستقیم: نیاز به کنترل دقیق بر مکانیک پیمایش فراتر از آنچه verticalScroll یا طرح‌بندی‌های Lazy ارائه می‌دهند.

بااستفاده از scrollableArea، فهرست‌های سفارشی چرخ‌مانند ایجاد کنید

نمونه زیر نحوه استفاده از scrollableArea را برای ساختن فهرست عمودی سفارشی نشان می‌دهد که در آن، موارد با دور شدن از مرکز کوچک‌تر می‌شوند و جلوه بصری «چرخ‌مانند» ایجاد می‌کنند. این نوع تبدیل وابسته به پیمایش، مورد استفاده عالی برای scrollableArea است.

شکل ۲. فهرست عمودی سفارشی‌شده بااستفاده از scrollableArea.

@Composable
private fun ScrollableAreaSample() {
    // ...
    Layout(
        modifier =
            Modifier
                .size(150.dp)
                .scrollableArea(scrollState, Orientation.Vertical)
                .background(Color.LightGray),
        // ...
    ) { measurables, constraints ->
        // ...
        // Update the maximum scroll value to not scroll beyond limits and stop when scroll
        // reaches the end.
        scrollState.maxValue = (totalHeight - viewportHeight).coerceAtLeast(0)

        // Position the children within the layout.
        layout(constraints.maxWidth, viewportHeight) {
            // The current vertical scroll position, in pixels.
            val scrollY = scrollState.value
            val viewportCenterY = scrollY + viewportHeight / 2

            var placeableLayoutPositionY = 0
            placeables.forEach { placeable ->
                // This sample applies a scaling effect to items based on their distance
                // from the center, creating a wheel-like effect.
                // ...
                // Place the item horizontally centered with a layer transformation for
                // scaling to achieve wheel-like effect.
                placeable.placeRelativeWithLayer(
                    x = constraints.maxWidth / 2 - placeable.width / 2,
                    // Offset y by the scroll position to make placeable visible in the viewport.
                    y = placeableLayoutPositionY - scrollY,
                ) {
                    scaleX = scaleFactor
                    scaleY = scaleFactor
                }
                // Move to the next item's vertical position.
                placeableLayoutPositionY += placeable.height
            }
        }
    }
}
// ...

اصلاح‌گر قابل‌پیمایش

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

When constructing ScrollableState you must provide a consumeScrollDelta function which will be invoked on each scroll step (by gesture input, smooth scrolling or flinging) with the delta in pixels. This function must return the amount of scrolling distance consumed, to ensure the event is properly propagated in cases where there are nested elements that have the scrollable modifier.

قطعه کد زیر اشاره‌ها را شناسایی می‌کند و مقدار عددی را برای جابه‌جایی نمایش می‌دهد، اما هیچ عنصری را جابه‌جا نمی‌کند:

@Composable
private fun ScrollableSample() {
    // actual composable state
    var offset by remember { mutableFloatStateOf(0f) }
    Box(
        Modifier
            .size(150.dp)
            .scrollable(
                orientation = Orientation.Vertical,
                // Scrollable state: describes how to consume
                // scrolling delta and update offset
                state = rememberScrollableState { delta ->
                    offset += delta
                    delta
                }
            )
            .background(Color.LightGray),
        contentAlignment = Alignment.Center
    ) {
        Text(offset.toString())
    }
}

عنصر میانای کاربر که فشار انگشت را تشخیص می‌دهد و مقدار عددی مکان انگشت را نمایش می‌دهد
شکل ۳.‏ عنصر میانای کاربر که فشار انگشت را تشخیص می‌دهد و مقدار عددی مکان انگشت را نمایش می‌دهد.