स्क्रोल करें

स्क्रोल मॉडिफ़ायर

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 ज़्यादा नैचुरल लगता है.

नीचे दी गई टेबल में, सामान्य स्थितियों के लिए डेल्टा के निशान की खास जानकारी दी गई है:

उपयोगकर्ता का जेस्चर

scrollable ने dispatchRawDelta को डेल्टा की रिपोर्ट भेजी

scrollableArea*ने dispatchRawDelta को डेल्टा की जानकारी दी

पॉइंटर ऊपर की ओर जाता है

नेगेटिव

सकारात्मक

पॉइंटर नीचे की ओर जाता है

सकारात्मक

नेगेटिव

पॉइंटर बाईं ओर मूव होता है

नेगेटिव

पॉज़िटिव (RTL के लिए नेगेटिव)

पॉइंटर RIGHT की ओर जाता है

सकारात्मक

नेगेटिव (दाएं से बाएं लिखी जाने वाली भाषाओं के लिए, पॉज़िटिव)

(*) scrollableArea डेल्टा साइन के बारे में जानकारी: scrollableArea से डेल्टा का साइन सिर्फ़ उल्टा नहीं होता. यह इन बातों को ध्यान में रखता है:

  1. ओरिएंटेशन: वर्टिकल या हॉरिज़ॉन्टल.
  2. LayoutDirection: एलटीआर या आरटीएल (खास तौर पर, हॉरिज़ॉन्टल स्क्रोलिंग के लिए ज़रूरी है).
  3. reverseScrolling फ़्लैग: इससे पता चलता है कि स्क्रोल करने की दिशा बदली गई है या नहीं.

स्क्रोल डेल्टा को उलटने के साथ-साथ, scrollableArea कॉन्टेंट को लेआउट की सीमाओं में काटता है और ओवरस्क्रोल इफ़ेक्ट की रेंडरिंग को मैनेज करता है. डिफ़ॉल्ट रूप से, यह LocalOverscrollFactory से मिले इफ़ेक्ट का इस्तेमाल करता है. OverscrollEffect पैरामीटर स्वीकार करने वाले scrollableArea ओवरलोड का इस्तेमाल करके, इसे पसंद के मुताबिक बनाया जा सकता है या बंद किया जा सकता है.

scrollableArea मॉडिफ़ायर का इस्तेमाल कब करें

आपको scrollableArea मॉडिफ़ायर का इस्तेमाल तब करना चाहिए, जब आपको कोई ऐसा कस्टम स्क्रोलिंग कॉम्पोनेंट बनाना हो जो horizontalScroll या verticalScroll मॉडिफ़ायर या लेज़ी लेआउट से सही तरीके से नहीं बनाया जा सकता. इसमें अक्सर इन मामलों से जुड़ी समस्याएं शामिल होती हैं:

  • कस्टम लेआउट लॉजिक: जब स्क्रोल की पोज़िशन के आधार पर, आइटम का क्रम डाइनैमिक तरीके से बदलता है.
  • यूनीक विज़ुअल इफ़ेक्ट: स्क्रोल करते समय बच्चों पर ट्रांसफ़ॉर्मेशन, स्केलिंग या अन्य इफ़ेक्ट लागू करना.
  • सीधे तौर पर कंट्रोल करना: स्क्रोलिंग के तरीके पर ज़्यादा कंट्रोल की ज़रूरत होती है. यह कंट्रोल, 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 बनाते समय, आपको एक 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())
    }
}

यूज़र इंटरफ़ेस (यूआई) एलिमेंट, जो उंगली के दबाने का पता लगाता है और उंगली की जगह के लिए संख्यात्मक वैल्यू दिखाता है
तीसरी इमेज. यूज़र इंटरफ़ेस (यूआई) का ऐसा एलिमेंट जो उंगली के दबाने का पता लगाता है और उंगली की जगह के लिए संख्या वाली वैल्यू दिखाता है.