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 প্যারামিটার হিসেবে এটি পাস করুন। আপনি এই রাজ্যে 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 ফাংশন ব্যবহার করে এইসব ভেরিয়েবলে হওয়া পরিবর্তন লক্ষ্য করতে এবং সেই অনুযায়ী ব্যবস্থা নিতে পারবেন। যেমন, প্রতিটি পৃষ্ঠা পরিবর্তনের সময় অ্যানালিটিক্স ইভেন্ট পাঠাতে, আপনি নিম্নলিখিত কাজ করতে পারেন:

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 ব্যবহার করতে পারেন। তারপর, বেছে নেওয়া পৃষ্ঠা থেকে দূরত্বের উপর ভিত্তি করে আপনি কন্টেন্টে ট্রান্সফর্মেশন এফেক্ট প্রয়োগ করতে পারবেন।

ছবি ৪। Pager কন্টেন্টে ট্রান্সফর্মেশন প্রয়োগ করা হচ্ছে

যেমন, আইটেমগুলি কেন্দ্র থেকে কত দূরে রয়েছে তার উপর ভিত্তি করে তাদের অস্বচ্ছতা অ্যাডজাস্ট করতে, পেজারের ভিতরে একটি আইটেমে 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)
    }
}

অটো-অ্যাডভান্সিং পেজার তৈরি করুন

Compose-এ পৃষ্ঠা নির্দেশক সহ অটো-অ্যাডভান্সিং পেজার কীভাবে তৈরি করতে হয় তা এই বিভাগে বর্ণনা করা হয়েছে। আইটেমের সংগ্রহ অটোমেটিক অনুভূমিকভাবে স্ক্রল করে, তবে ব্যবহারকারীরা ম্যানুয়ালি আইটেমগুলির মধ্যে সোয়াইপ করতে পারেন। ব্যবহারকারী পেজারের সাথে ইন্টার‍্যাক্ট করলে, এটি অটোমেটিক প্রগ্রেশন বন্ধ করে দেয়।

প্রাথমিক উদাহরণ

একসাথে, নিম্নলিখিত স্নিপেটগুলি একটি ভিজ্যুয়াল ইন্ডিকেটর সহ একটি বেসিক অটো-অ্যাডভান্সিং পেজার ইমপ্লিমেন্টেশন তৈরি করে, যেখানে প্রতিটি পৃষ্ঠা একটি আলাদা রঙ হিসাবে রেন্ডার করে:

@Composable
fun AutoAdvancePager(pageItems: List<Color>, modifier: Modifier = Modifier) {
    Box(modifier = Modifier.fillMaxSize()) {
        val pagerState = rememberPagerState(pageCount = { pageItems.size })
        val pagerIsDragged by pagerState.interactionSource.collectIsDraggedAsState()

        val pageInteractionSource = remember { MutableInteractionSource() }
        val pageIsPressed by pageInteractionSource.collectIsPressedAsState()

        // Stop auto-advancing when pager is dragged or one of the pages is pressed
        val autoAdvance = !pagerIsDragged && !pageIsPressed

        if (autoAdvance) {
            LaunchedEffect(pagerState, pageInteractionSource) {
                while (true) {
                    delay(2000)
                    val nextPage = (pagerState.currentPage + 1) % pageItems.size
                    pagerState.animateScrollToPage(nextPage)
                }
            }
        }

        HorizontalPager(
            state = pagerState
        ) { page ->
            Text(
                text = "Page: $page",
                textAlign = TextAlign.Center,
                modifier = modifier
                    .fillMaxSize()
                    .background(pageItems[page])
                    .clickable(
                        interactionSource = pageInteractionSource,
                        indication = LocalIndication.current
                    ) {
                        // Handle page click
                    }
                    .wrapContentSize(align = Alignment.Center)
            )
        }

        PagerIndicator(pageItems.size, pagerState.currentPage)
    }
}

কোড সম্পর্কে গুরুত্বপূর্ণ পয়েন্ট

  • AutoAdvancePager ফাংশন অটোমেটিক অ্যাডভান্সমেন্ট সহ অনুভূমিক পেজিং ভিউ তৈরি করে। এটি ইনপুট হিসেবে Colorটি অবজেক্টের তালিকা নেয়, যেগুলি প্রতিটি পৃষ্ঠার ব্যাকগ্রাউন্ড কালার হিসেবে ব্যবহার করা হয়।
  • pagerState, rememberPagerState ব্যবহার করে তৈরি করা হয়, যা পেজারের স্ট্যাটাস ধরে রাখে।
  • pagerIsDragged এবং pageIsPressed ব্যবহারকারীর ইন্টার‍্যাকশন ট্র্যাক করে।
  • LaunchedEffect প্রতি দুই সেকেন্ডে পেজারকে অটো-অ্যাডভান্স করে, যদি না ব্যবহারকারী পেজারটি টেনে আনেন বা পৃষ্ঠাগুলির একটিতে প্রেস করেন।
  • HorizontalPager পৃষ্ঠার একটি তালিকা দেখায়, যার প্রতিটিতে একটি Text কম্পোজেবল পৃষ্ঠার নম্বর দেখায়। মডিফায়ার পৃষ্ঠাটি পূরণ করে, pageItems থেকে ব্যাকগ্রাউন্ডের রঙ সেট করে এবং পৃষ্ঠাটিকে ক্লিকযোগ্য করে তোলে।

@Composable
fun PagerIndicator(pageCount: Int, currentPageIndex: Int, modifier: Modifier = Modifier) {
    Box(modifier = Modifier.fillMaxSize()) {
        Row(
            modifier = Modifier
                .wrapContentHeight()
                .fillMaxWidth()
                .align(Alignment.BottomCenter)
                .padding(bottom = 8.dp),
            horizontalArrangement = Arrangement.Center
        ) {
            repeat(pageCount) { iteration ->
                val color = if (currentPageIndex == iteration) Color.DarkGray else Color.LightGray
                Box(
                    modifier = modifier
                        .padding(2.dp)
                        .clip(CircleShape)
                        .background(color)
                        .size(16.dp)
                )
            }
        }
    }
}

কোড সম্পর্কে গুরুত্বপূর্ণ পয়েন্ট

  • একটি Box কম্পোজেবল রুট এলিমেন্ট হিসেবে কাজ করে এবং এতে পৃষ্ঠা নির্দেশক অনুভূমিকভাবে সাজানোর জন্য একটি Row থাকে।
  • কাস্টম পৃষ্ঠা ইন্ডিকেটর বৃত্তের সারি হিসেবে দেখানো হয়, যেখানে প্রতিটি Box CircleShape-এ ক্লিপ করা একটি পৃষ্ঠা দেখায়।
  • বর্তমান পৃষ্ঠার বৃত্তটি DarkGray হিসেবে রঙিন করা হয়েছে, যেখানে অন্যান্য বৃত্তগুলি LightGray। currentPageIndex প্যারামিটার নির্ধারণ করে যে কোন সার্কেল গাঢ় ধূসর রঙে রেন্ডার করা হবে।

ফলাফল

এই ভিডিওতে আগের স্নিপেট থেকে অটোমেটিক এগিয়ে যাওয়া বেসিক পেজার দেখানো হয়েছে:

ছবি ৮। একটি অটো-অ্যাডভান্সিং পেজার, যেখানে প্রতিটি পৃষ্ঠা পরিবর্তনের মধ্যে দুই সেকেন্ডের বিলম্ব থাকে।

অতিরিক্ত রিসোর্স