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 को शून्य से ज़्यादा मान पर सेट करें.

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

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

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

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

उदाहरण के लिए, आइटम की अपारदर्शिता (ओपैसिटी) को इस आधार पर अडजस्ट करना कि वे बीच में, alpha को इनका इस्तेमाल करके बदलें Modifier.graphicsLayer पेजर में मौजूद किसी आइटम पर:

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