Wear OS-এর জন্য Composer দিয়ে পেজিং

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

Wear OS Material 3-এর Compose-এ, 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 এ থাকা পেজের অফসেটের উপর ভিত্তি করে ম্যাটেরিয়াল ৩ ট্রানজিশন অ্যানিমেশন (স্কেলিং এবং স্ক্রিম এফেক্ট) প্রয়োগ করার জন্য প্রতিটি স্বতন্ত্র পেজকে র‍্যাপ করে।
  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 নেস্ট করুন।

ম্যাটেরিয়াল ৩ স্প্রিং মোশন ফিজিক্স এবং রেসপন্সিভ পেজ স্ন্যাপিং ( HighSnapPositionalThreshold ) প্রয়োগ করতে flingBehavior জন্য PagerScaffoldDefaults.snapWithSpringFlingBehavior ব্যবহার করুন। ডিফল্টরূপে, 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() তৈরি করুন এবং সেটিকে ভেতরের ScreenScaffoldTransformingLazyColumn এ পাস করুন:

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) )। flingBehaviorPagerScaffoldDefaults.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.snapFlingBehaviormaxFlingPages = 0 এবং snapPositionalThreshold = PagerScaffoldDefaults.LowSnapPositionalThreshold পাস করুন, যাতে পৃষ্ঠা উল্টানোর জন্য স্ক্রিনের একটি বড় অংশ জুড়ে ইচ্ছাকৃতভাবে ড্র্যাগ করার প্রয়োজন হয়।
  • আপনি যদি রোটারি পেজ স্ন্যাপিং সক্রিয় করেন, তাহলে পরবর্তী পৃষ্ঠায় স্ন্যাপ করার আগে আরও বেশি ঘূর্ণনের প্রয়োজন হলে RotaryScrollableDefaults.snapBehaviorsnapSensitivity = RotaryScrollableDefaults.LowSnapSensitivity সেট করুন।
@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 দেখুন।