Compose में पेजर

कॉम्पोनेंट को बाईं और दाईं या ऊपर और नीचे की ओर फ़्लिप करने के लिए, HorizontalPager और VerticalPager का इस्तेमाल करें. इन कॉम्पोज़ेबल के फ़ंक्शन, व्यू सिस्टम में मौजूद ViewPager से मिलते-जुलते होते हैं. डिफ़ॉल्ट रूप से, HorizontalPager स्क्रीन की पूरी चौड़ाई पर दिखता है, VerticalPager पूरी ऊंचाई पर दिखता है, और पेजर एक बार में सिर्फ़ एक पेज फ़्लिंग करते हैं. इन डिफ़ॉल्ट वैल्यू को कॉन्फ़िगर किया जा सकता है.

HorizontalPager

ऐसा पेजर बनाने के लिए जो हॉरिज़ॉन्टल तौर पर बाईं और दाईं ओर स्क्रोल करता है, HorizontalPager का इस्तेमाल करें:

पहली इमेज. HorizontalPager
का डेमो

// Display 10 items
val pagerState = rememberPagerState(pageCount = {
    10
})
HorizontalPager(state = pagerState) { page ->
    // Our page content
    Text(
        text = "Page: $page",
        modifier = Modifier.fillMaxWidth()
    )
}

VerticalPager

ऊपर और नीचे स्क्रोल करने वाला पेजर बनाने के लिए, VerticalPager का इस्तेमाल करें:

दूसरी इमेज. VerticalPager
का डेमो

// Display 10 items
val pagerState = rememberPagerState(pageCount = {
    10
})
VerticalPager(state = pagerState) { page ->
    // Our page content
    Text(
        text = "Page: $page",
        modifier = Modifier.fillMaxWidth()
    )
}

लेज़ी क्रिएशन

HorizontalPager और VerticalPager, दोनों में पेजों को लाज़ीली कॉम्पोज़ किया जाता है और ज़रूरत पड़ने पर लेआउट किया जाता है. जब उपयोगकर्ता पेजों पर स्क्रोल करता है, तो कॉम्पोज़ेबल उन सभी पेजों को हटा देता है जिनकी अब ज़रूरत नहीं है.

स्क्रीन के बाहर ज़्यादा पेज लोड करना

डिफ़ॉल्ट रूप से, पेजर सिर्फ़ स्क्रीन पर दिखने वाले पेज लोड करता है. स्क्रीन के बाहर ज़्यादा पेज लोड करने के लिए, beyondBoundsPageCount को शून्य से ज़्यादा की वैल्यू पर सेट करें.

पेजर में किसी आइटम पर स्क्रोल करना

पेजर में किसी पेज पर स्क्रोल करने के लिए, rememberPagerState() का इस्तेमाल करके एक PagerState ऑब्जेक्ट बनाएं और उसे पेजर में state पैरामीटर के तौर पर पास करें. CoroutineScope में जाकर, इस स्थिति पर PagerState#scrollToPage() को कॉल किया जा सकता है:

val pagerState = rememberPagerState(pageCount = {
    10
})
HorizontalPager(state = pagerState) { page ->
    // Our page content
    Text(
        text = "Page: $page",
        modifier = Modifier
            .fillMaxWidth()
            .height(100.dp)
    )
}

// scroll to page
val coroutineScope = rememberCoroutineScope()
Button(onClick = {
    coroutineScope.launch {
        // Call scroll to on pagerState
        pagerState.scrollToPage(5)
    }
}, modifier = Modifier.align(Alignment.BottomCenter)) {
    Text("Jump to Page 5")
}

अगर आपको पेज पर ऐनिमेशन जोड़ना है, तो PagerState#animateScrollToPage() फ़ंक्शन का इस्तेमाल करें:

val pagerState = rememberPagerState(pageCount = {
    10
})

HorizontalPager(state = pagerState) { page ->
    // Our page content
    Text(
        text = "Page: $page",
        modifier = Modifier
            .fillMaxWidth()
            .height(100.dp)
    )
}

// scroll to page
val coroutineScope = rememberCoroutineScope()
Button(onClick = {
    coroutineScope.launch {
        // Call scroll to on pagerState
        pagerState.animateScrollToPage(5)
    }
}, modifier = Modifier.align(Alignment.BottomCenter)) {
    Text("Jump to Page 5")
}

पेज की स्थिति में हुए बदलावों के बारे में सूचना पाना

PagerState में, पेजों की जानकारी वाली तीन प्रॉपर्टी होती हैं: currentPage, settledPage, और targetPage.

  • currentPage: स्नैप किए गए पॉइंट के सबसे करीब का पेज. डिफ़ॉल्ट रूप से, स्नैप करने की जगह लेआउट की शुरुआत में होती है.
  • settledPage: जब कोई ऐनिमेशन या स्क्रोलिंग नहीं चल रही है, तब पेज का नंबर. यह currentPage प्रॉपर्टी से अलग है. अगर पेज, स्नैप पोज़िशन के काफ़ी करीब है, तो currentPage तुरंत अपडेट हो जाता है. हालांकि, settledPage तब तक एक जैसा ही रहता है, जब तक सभी ऐनिमेशन चलना बंद नहीं हो जाते.
  • targetPage: स्क्रोल करने के दौरान, स्क्रीन पर दिखने वाले कॉन्टेंट की स्टॉप पोज़िशन.

इन वैरिएबल में हुए बदलावों को देखने और उन पर कार्रवाई करने के लिए, snapshotFlow फ़ंक्शन का इस्तेमाल किया जा सकता है. उदाहरण के लिए, हर पेज में बदलाव होने पर Analytics इवेंट भेजने के लिए, ये काम किए जा सकते हैं:

val pagerState = rememberPagerState(pageCount = {
    10
})

LaunchedEffect(pagerState) {
    // Collect from the a snapshotFlow reading the currentPage
    snapshotFlow { pagerState.currentPage }.collect { page ->
        // Do something with each page change, for example:
        // viewModel.sendPageSelectedEvent(page)
        Log.d("Page change", "Page changed to $page")
    }
}

VerticalPager(
    state = pagerState,
) { page ->
    Text(text = "Page: $page")
}

पेज इंडिकेटर जोड़ना

किसी पेज में इंडिकेटर जोड़ने के लिए, PagerState ऑब्जेक्ट का इस्तेमाल करें. इससे आपको यह जानकारी मिलेगी कि पेजों में से कौनसा पेज चुना गया है. साथ ही, अपना कस्टम इंडिकेटर भी बनाया जा सकता है.

उदाहरण के लिए, अगर आपको एक आसान सर्कल इंडिकेटर चाहिए, तो सर्कल की संख्या को दोहराया जा सकता है. साथ ही, pagerState.currentPage का इस्तेमाल करके, पेज के चुने जाने के आधार पर सर्कल का रंग बदला जा सकता है:

val pagerState = rememberPagerState(pageCount = {
    4
})
HorizontalPager(
    state = pagerState,
    modifier = Modifier.fillMaxSize()
) { page ->
    // Our page content
    Text(
        text = "Page: $page",
    )
}
Row(
    Modifier
        .wrapContentHeight()
        .fillMaxWidth()
        .align(Alignment.BottomCenter)
        .padding(bottom = 8.dp),
    horizontalArrangement = Arrangement.Center
) {
    repeat(pagerState.pageCount) { iteration ->
        val color = if (pagerState.currentPage == iteration) Color.DarkGray else Color.LightGray
        Box(
            modifier = Modifier
                .padding(2.dp)
                .clip(CircleShape)
                .background(color)
                .size(16.dp)
        )
    }
}

कॉन्टेंट के नीचे सर्कल इंडिकेटर दिखाने वाला पेजर
तीसरी इमेज. पेजर, जो कॉन्टेंट के नीचे सर्कल इंडिकेटर दिखाता है

कॉन्टेंट में आइटम स्क्रोल करने के इफ़ेक्ट लागू करना

पेजर आइटम पर इफ़ेक्ट लागू करने के लिए, स्क्रोल पोज़िशन का इस्तेमाल करना एक सामान्य उदाहरण है. यह जानने के लिए कि कोई पेज, फ़िलहाल चुने गए पेज से कितना दूर है, PagerState.currentPageOffsetFraction का इस्तेमाल किया जा सकता है. इसके बाद, चुने गए पेज से दूरी के आधार पर, अपने कॉन्टेंट पर ट्रांसफ़ॉर्मेशन इफ़ेक्ट लागू किए जा सकते हैं.

चौथी इमेज. पेजर कॉन्टेंट में बदलाव करना

उदाहरण के लिए, आइटम के बीच के फ़ासले के आधार पर, उनके अपार्च्युटी लेवल में बदलाव करने के लिए, पेजर में मौजूद किसी आइटम पर Modifier.graphicsLayer का इस्तेमाल करके alpha बदलें:

val pagerState = rememberPagerState(pageCount = {
    4
})
HorizontalPager(state = pagerState) { page ->
    Card(
        Modifier
            .size(200.dp)
            .graphicsLayer {
                // Calculate the absolute offset for the current page from the
                // scroll position. We use the absolute value which allows us to mirror
                // any effects for both directions
                val pageOffset = (
                    (pagerState.currentPage - page) + pagerState
                        .currentPageOffsetFraction
                    ).absoluteValue

                // We animate the alpha, between 50% and 100%
                alpha = lerp(
                    start = 0.5f,
                    stop = 1f,
                    fraction = 1f - pageOffset.coerceIn(0f, 1f)
                )
            }
    ) {
        // Card content
    }
}

कस्टम पेज साइज़

डिफ़ॉल्ट रूप से, HorizontalPager और VerticalPager, क्रमशः पूरी चौड़ाई या पूरी ऊंचाई लेते हैं. pageSize वैरिएबल को Fixed, Fill (डिफ़ॉल्ट) या कस्टम साइज़ कैलकुलेशन पर सेट किया जा सकता है.

उदाहरण के लिए, 100.dp की फ़िक्स्ड विड्थ वाला पेज सेट करने के लिए:

val pagerState = rememberPagerState(pageCount = {
    4
})
HorizontalPager(
    state = pagerState,
    pageSize = PageSize.Fixed(100.dp)
) { page ->
    // page content
}

व्यूपोर्ट के साइज़ के आधार पर पेजों का साइज़ तय करने के लिए, पेज के साइज़ का हिसाब लगाने के लिए कस्टम फ़ॉर्मूला का इस्तेमाल करें. कस्टम PageSize ऑब्जेक्ट बनाएं और आइटम के बीच के स्पेस को ध्यान में रखते हुए, availableSpace को तीन से भाग दें:

private val threePagesPerViewport = object : PageSize {
    override fun Density.calculateMainAxisPageSize(
        availableSpace: Int,
        pageSpacing: Int
    ): Int {
        return (availableSpace - 2 * pageSpacing) / 3
    }
}

कॉन्टेंट पैडिंग

HorizontalPager और VerticalPager, दोनों की मदद से कॉन्टेंट पैडिंग में बदलाव किया जा सकता है. इससे, पेजों के ज़्यादा से ज़्यादा साइज़ और अलाइनमेंट पर असर पड़ता है.

उदाहरण के लिए, start पैडिंग सेट करने पर, पेजों को आखिर में अलाइन किया जाता है:

शुरू में पैडिंग वाला पेजर, जिसमें कॉन्टेंट आखिर में अलाइन किया गया है

val pagerState = rememberPagerState(pageCount = {
    4
})
HorizontalPager(
    state = pagerState,
    contentPadding = PaddingValues(start = 64.dp),
) { page ->
    // page content
}

start और end, दोनों पैडिंग को एक ही वैल्यू पर सेट करने से, आइटम को हॉरिज़ॉन्टल तौर पर बीच में रखा जाता है:

पेज पर कॉन्टेंट को बीच में दिखाने के लिए, शुरू और आखिर में पैडिंग

val pagerState = rememberPagerState(pageCount = {
    4
})
HorizontalPager(
    state = pagerState,
    contentPadding = PaddingValues(horizontal = 32.dp),
) { page ->
    // page content
}

end पैडिंग सेट करने पर, पेजों को शुरुआत में अलाइन किया जाता है:

शुरू और खत्म होने के पैडिंग वाला पेजर, जिसमें कॉन्टेंट को शुरू से अलाइन किया गया है

val pagerState = rememberPagerState(pageCount = {
    4
})
HorizontalPager(
    state = pagerState,
    contentPadding = PaddingValues(end = 64.dp),
) { page ->
    // page content
}

VerticalPager के लिए मिलते-जुलते इफ़ेक्ट पाने के लिए, top और bottom वैल्यू सेट की जा सकती हैं. वैल्यू 32.dp का इस्तेमाल यहां सिर्फ़ उदाहरण के तौर पर किया गया है. आपके पास हर पैडिंग डाइमेंशन को किसी भी वैल्यू पर सेट करने का विकल्प है.

स्क्रोल करने के तरीके को पसंद के मुताबिक बनाना

डिफ़ॉल्ट HorizontalPager और VerticalPager कॉम्पोज़ेबल से यह पता चलता है कि पेजर के साथ स्क्रोल करने वाले जेस्चर कैसे काम करते हैं. हालांकि, pagerSnapDistance या flingBehavior जैसे डिफ़ॉल्ट आइकॉन को पसंद के मुताबिक बनाया जा सकता है और उनमें बदलाव किया जा सकता है.

स्नैप की दूरी

डिफ़ॉल्ट रूप से, HorizontalPager और VerticalPager सेट करते हैं कि एक बार में कितने पेज तक फ़्लिंग जेस्चर से स्क्रोल किया जा सकता है. इसे बदलने के लिए, flingBehavior पर pagerSnapDistance सेट करें:

val pagerState = rememberPagerState(pageCount = { 10 })

val fling = PagerDefaults.flingBehavior(
    state = pagerState,
    pagerSnapDistance = PagerSnapDistance.atMost(10)
)

Column(modifier = Modifier.fillMaxSize()) {
    HorizontalPager(
        state = pagerState,
        pageSize = PageSize.Fixed(200.dp),
        beyondViewportPageCount = 10,
        flingBehavior = fling
    ) {
        PagerSampleItem(page = it)
    }
}