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

اصلاح‌کننده‌های 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 یا چیدمان‌های «تنبل» ارائه نمی‌شود، باید از اصلاح‌کننده scrollableArea استفاده کنید. این اغلب شامل مواردی با موارد زیر می‌شود:

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

بااستفاده از 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 به کاربر واگذار می‌شود که برای عملکرد صحیح این اصلاح‌گر الزامی است.

هنگام ساختن ScrollableState باید تابع consumeScrollDelta ارائه دهید که در هر مرحله پیمایش (با ورودی اشاره، پیمایش آرام، یا پرتاب) با دلتا در پیکسل فراخوانی می‌شود. این تابع باید مقدار پیمایش مصرف‌شده را برگرداند تا مطمئن شود رویداد در مواردی که عناصر تودرتو با اصلاح‌گر scrollable وجود دارد به‌درستی منتشر می‌شود.

تکه کد زیر ژست‌ها را تشخیص می‌دهد و مقدار عددی را برای انحراف نمایش می‌دهد، اما هیچ عنصری را منحرف نمی‌کند:

@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())
    }
}

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