Wear OS-এর জন্য Compose-এর মাধ্যমে পেজিং

পেজিংয়ের মাধ্যমে Wear OS ডিভাইসে ব্যবহারকারীরা আলাদা আলাদা, ফুল-স্ক্রিন পৃষ্ঠার মধ্যে অনুভূমিক বা উল্লম্বভাবে সোয়াইপ করতে পারেন। সাধারণ ব্যবহারের ক্ষেত্রে, কোনও এক্সারসাইজ অ্যাপে ওয়ার্কআউট মেট্রিক ও মিডিয়া কন্ট্রোলের মধ্যে সোয়াইপ করা অথবা একাধিক পৃষ্ঠা ফ্লোতে স্টেপ করা অন্তর্ভুক্ত।

Compose for Wear OS Material 3-এ, HorizontalPagerScaffold এবং VerticalPagerScaffold পেজার লেআউট কোঅর্ডিনেট করে, অটোমেটিক পেজ ইন্ডিকেটর পজিশন করে এবং TimeText-এর মাধ্যমে ট্রানজিশন ম্যানেজ করে। প্রতিটি পৃষ্ঠা AnimatedPage কম্পোজ করার উপযুক্ত আইটেমের মধ্যে মোড়ানো থাকে, যা স্কেলিং, রাউন্ডেড কর্নার মর্ফিং এবং স্ক্রিম এফেক্ট প্রয়োগ করে, কারণ পৃষ্ঠাগুলি রাউন্ড ডিসপ্লে জুড়ে ট্রানজিশন করে।

নিম্নলিখিত অ্যানিমেশন থেকে কীভাবে HorizontalPagerScaffold এবং AnimatedPage হরাইজন্টাল সোয়াইপের সময় পৃষ্ঠাগুলি স্কেল ও অ্যানিমেট করে তা দেখতে পাবেন:

পেজিংয়ের জন্য স্ক্যাফোল্ড হায়ারার্কি

Material 3-এ পেজ নম্বর সহ স্ক্রিন লেআউট ডিজাইন করার সময়—বাঁদিকে বা ডানদিকে (HorizontalPager) অথবা উপরে বা নিচে (VerticalPager) সোয়াইপ করা হোক না কেন—বাইরের কন্টেনার থেকে ভিতরের কন্টেন্ট পর্যন্ত নিম্নলিখিত কম্পোনেন্ট হায়ারার্কি ব্যবহার করুন:

  1. AppScaffold: আপনার অ্যাপের মূল অংশে থাকা সবচেয়ে বাইরের কন্টেনার (প্রতিটি অ্যাপে শুধুমাত্র একটি ব্যবহার করুন)। এটি গ্লোবাল TimeText ওভারলে অ্যাঙ্কর করে যাতে পৃষ্ঠা ট্রানজিশন ও সোয়াইপ-টু-ডিসমিস জেসচারের সময় ঘড়িটি স্ক্রিনের উপরে স্থির থাকে।
  2. HorizontalPagerScaffold বা VerticalPagerScaffold: পেজার লেভেলে AppScaffold-এর মধ্যে প্লেস করা হয়েছে। এটি TimeText এবং HorizontalPageIndicator বা VerticalPageIndicator-এর মধ্যে ট্রানজিশন কোঅর্ডিনেট করে।
  3. HorizontalPager বা VerticalPager: শেয়ার করা PagerState ব্যবহার করে সোয়াইপ জেসচার, ফ্লিং ফিজিক্স ও রোটারি ইনপুট স্ন্যাপিং ম্যানেজ করে এমন ফাউন্ডেশন পেজার কন্টেনার।
  4. AnimatedPage: পেজারের পেজ কন্টেন্ট ল্যাম্বডার মধ্যে প্লেস করা হয়। PagerState-এ পৃষ্ঠার অফসেটের উপর ভিত্তি করে Material 3 ট্রানজিশন অ্যানিমেশন (স্কেলিং ও স্ক্রিম এফেক্ট) প্রয়োগ করতে এটি প্রতিটি স্বতন্ত্র পৃষ্ঠা র‍্যাপ করে।
  5. ScreenScaffold: প্রতিটি ব্যক্তিগত পৃষ্ঠার জন্য ভিতরে AnimatedPage প্লেস করা হয়েছে। কারণ, প্রতিটি পৃষ্ঠায় নিজস্ব ভার্টিকালি স্ক্রল করা যায় এমন তালিকা (যেমন, TransformingLazyColumn) বা নিজস্ব EdgeButton থাকতে পারে। প্রতিটি পৃষ্ঠার মধ্যে ScreenScaffold নেস্ট করা হলে তা নিশ্চিত করে যে ভার্টিক্যাল স্ক্রল ইন্ডিকেটর, এজ বোতাম ও contentPadding সেই নির্দিষ্ট পৃষ্ঠার অংশ এবং সেটির সাথে মসৃণভাবে অ্যানিমেট করে।
AppScaffold (1 per app: anchors global TimeText)
 └── HorizontalPagerScaffold / VerticalPagerScaffold (manages PageIndicator)
      └── HorizontalPager / VerticalPager (manages PagerState & fling behavior)
           └── AnimatedPage (applies scaling & scrim transitions per page)
                └── ScreenScaffold (1 per page: ScrollIndicator & EdgeButton)
                     └── Page Content (Column or TransformingLazyColumn)

অনুভূমিক পেজার প্রয়োগ করা

Material 3-এ অনুভূমিক পেজার প্রয়োগ করতে, আপনার অ্যাপের AppScaffold মধ্যে HorizontalPagerScaffold, HorizontalPager, AnimatedPage ও ScreenScaffold নেস্ট করুন।

Material 3 স্প্রিং মোশন ফিজিক্স ও রেসপন্সিভ পৃষ্ঠা স্ন্যাপিং (HighSnapPositionalThreshold) প্রয়োগ করতে PagerScaffoldDefaults.snapWithSpringFlingBehavior flingBehavior ব্যবহার করুন। ডিফল্ট হিসেবে, HorizontalPager রোটারি পৃষ্ঠা স্ক্রলিং (rotaryScrollableBehavior = null) বন্ধ করে দেয়, এর ফলে অ্যাক্টিভ পৃষ্ঠার মধ্যে ভার্টিক্যাল তালিকা (যেমন, TransformingLazyColumn) স্ক্রল করতে রোটেটিং ক্রাউন বা বেজেল ইনপুট ব্যবহার করা যায়।

নিচের নমুনাটি একটি সম্পূর্ণ HorizontalPagerScaffold সেট-আপের ডেমো দেখাচ্ছে:

@Composable
fun HorizontalPagerScaffoldSample(navigateBack: () -> Unit) {
    AppScaffold {
        val pagerState = rememberPagerState(pageCount = { 10 })

        HorizontalPagerScaffold(pagerState = pagerState) {
            HorizontalPager(
                state = pagerState,
                flingBehavior =
                    PagerScaffoldDefaults.snapWithSpringFlingBehavior(
                        state = pagerState
                    ),
            ) { page ->
                AnimatedPage(pageIndex = page, pagerState = pagerState) {
                    ScreenScaffold {
                        Column(
                            modifier = Modifier.fillMaxSize(),
                            horizontalAlignment = Alignment.CenterHorizontally,
                            verticalArrangement = Arrangement.Center,
                        ) {
                            Text(text = "Page #$page")
                            Spacer(modifier = Modifier.height(8.dp))
                            Text(text = "Swipe left and right")
                            if (page == 0) {
                                Spacer(modifier = Modifier.height(16.dp))
                                Button(onClick = navigateBack) { Text("Exit") }
                            }
                        }
                    }
                }
            }
        }
    }
}

আপনার হরিজন্টাল পেজারের মধ্যে থাকা কোনও পৃষ্ঠায় TransformingLazyColumn থাকলে, সেই পৃষ্ঠার স্কোপের মধ্যে একটি আলাদা rememberTransformingLazyColumnState() তৈরি করুন এবং সেটি ভেতরের ScreenScaffold ও TransformingLazyColumn-এ পাস করুন:

AppScaffold {
    val pagerState = rememberPagerState(pageCount = { 10 })

    HorizontalPagerScaffold(pagerState = pagerState) {
        HorizontalPager(
            state = pagerState,
            flingBehavior =
                PagerScaffoldDefaults.snapWithSpringFlingBehavior(
                    state = pagerState
                ),
        ) { page ->
            AnimatedPage(pageIndex = page, pagerState = pagerState) {
                val columnState = rememberTransformingLazyColumnState()
                val transformationSpec = rememberTransformationSpec()

                ScreenScaffold(
                    scrollState = columnState,
                ) { contentPadding ->
                    TransformingLazyColumn(
                        state = columnState,
                        contentPadding = contentPadding,
                    ) {
                        item {
                            ListHeader(
                                modifier = Modifier
                                    .fillMaxWidth()
                                    .transformedHeight(this, transformationSpec)
                                    .minimumVerticalContentPadding(
                                        ListHeaderDefaults.minimumTopListContentPadding
                                    ),
                                transformation = SurfaceTransformation(transformationSpec),
                            ) {
                                Text(text = "Pager sample")
                            }
                        }
                        item {
                            Card(
                                modifier = Modifier
                                    .fillMaxWidth()
                                    .transformedHeight(this, transformationSpec)
                                    .minimumVerticalContentPadding(
                                        CardDefaults.minimumVerticalListContentPadding
                                    ),
                                transformation = SurfaceTransformation(transformationSpec),
                            ) {
                                if (page == 0) {
                                    Text(text = "Page #$page. Swipe right")
                                } else {
                                    Text(text = "Page #$page. Swipe left and right")
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

ভার্টিক্যাল পেজার প্রয়োগ করা

ভার্টিক্যাল পেজার ব্যবহারকারীদের ঘড়ির রোটেটিং সাইড বোতাম বা বেজেল ব্যবহার করে পৃষ্ঠাগুলির মধ্যে উপরে ও নিচে সোয়াইপ করতে বা সেগুলির মধ্যে দিয়ে যেতে দেয়।

HorizontalPager-এর মতো নয়, VerticalPager ডিফল্ট (RotaryScrollableDefaults.snapBehavior(state)) হিসেবে রোটারি পৃষ্ঠা স্ন্যাপিং চালু করে। flingBehavior-এ PagerScaffoldDefaults.snapWithSpringFlingBehavior পাস করুন এবং AnimatedPage ও ScreenScaffold-এ প্রতিটি পৃষ্ঠা মোড়ান:

@Composable
fun VerticalPagerScaffoldSample() {
    AppScaffold {
        val pagerState = rememberPagerState(pageCount = { 10 })

        VerticalPagerScaffold(pagerState = pagerState) {
            VerticalPager(
                state = pagerState,
                flingBehavior =
                    PagerScaffoldDefaults.snapWithSpringFlingBehavior(
                        state = pagerState
                    ),
            ) { page ->
                AnimatedPage(pageIndex = page, pagerState = pagerState) {
                    ScreenScaffold {
                        Column(
                            modifier = Modifier.fillMaxSize(),
                            horizontalAlignment = Alignment.CenterHorizontally,
                            verticalArrangement = Arrangement.Center,
                        ) {
                            Text(text = "Page #$page")
                            Spacer(modifier = Modifier.height(8.dp))
                            Text(text = "Swipe up and down")
                        }
                    }
                }
            }
        }
    }
}

পেজার বিহেভিয়র কাস্টমাইজ করা

আপনার অ্যাপের ইন্টার‍্যাকশন সংক্রান্ত প্রয়োজন মেটাতে, আপনি HorizontalPagerScaffold ও VerticalPagerScaffold-এর স্ন্যাপিং সংবেদনশীলতা কাস্টমাইজ করতে পারবেন।

ওয়ার্কআউটের জন্য স্ন্যাপ সেন্সিটিভিটি অ্যাডজাস্ট করা

ওয়ার্কআউট বা হাই-মোশন অ্যাক্টিভিটির সময় ব্যবহারকারীর গ্রস মোটর কন্ট্রোল সীমিত থাকে, তাই ভুলবশত টাচ বা সামান্য ক্রাউন ঘোরানোর ফলে অনিচ্ছাকৃতভাবে পৃষ্ঠা পরিবর্তন হয়ে যেতে পারে। এইসব স্ক্রিনের জন্য, কম স্ন্যাপ সংবেদনশীলতা সহ আপনার পেজার কনফিগার করুন:

  • PagerDefaults.snapFlingBehavior পাস করুন maxFlingPages = 0 এবং snapPositionalThreshold = PagerScaffoldDefaults.LowSnapPositionalThreshold তাই পৃষ্ঠা উল্টানোর জন্য স্ক্রিনের একটি বড় অংশ জুড়ে ইচ্ছাকৃতভাবে টানতে হবে।
  • আপনি রোটারি পেজ স্ন্যাপিং চালু করলে, পরবর্তী পৃষ্ঠায় স্ন্যাপ করার আগে আরও বেশি রোটেট করার প্রয়োজন হলে, snapSensitivity = RotaryScrollableDefaults.LowSnapSensitivityin RotaryScrollableDefaults.snapBehavior সেট করুন।
@Composable
fun HorizontalPagerScaffoldWithLowSensitivitySample(navigateBack: () -> Unit) {
    AppScaffold {
        val pagerState = rememberPagerState(pageCount = { 3 })

        HorizontalPagerScaffold(pagerState = pagerState) {
            HorizontalPager(
                state = pagerState,
                flingBehavior =
                    PagerDefaults.snapFlingBehavior(
                        state = pagerState,
                        maxFlingPages = 0,
                        snapPositionalThreshold =
                            PagerScaffoldDefaults.LowSnapPositionalThreshold,
                    ),
                rotaryScrollableBehavior =
                    RotaryScrollableDefaults.snapBehavior(
                        pagerState = pagerState,
                        snapSensitivity =
                            RotaryScrollableDefaults.LowSnapSensitivity,
                    ),
            ) { page ->
                AnimatedPage(pageIndex = page, pagerState = pagerState) {
                    ScreenScaffold {
                        // Page content
                    }
                }
            }
        }
    }
}

সম্পূর্ণ স্যাম্পেল প্রয়োগের জন্য, android/snippets রেপোজিটরিতে Pager.kt এবং AndroidX রেপোজিটরিতে PagerScaffoldSample.kt দেখুন।