صفحه‌بندی با Compose برای Wear OS

قابلیت صفحه‌بندی به کاربران اجازه می‌دهد تا در دستگاه‌های Wear OS، بین صفحات مجزا و تمام‌صفحه، به‌صورت افقی یا عمودی جابه‌جا شوند. موارد استفاده رایج شامل جابه‌جایی بین معیارهای تمرین و کنترل‌های رسانه در یک برنامه ورزشی یا پیمایش بین جریان‌های چندصفحه‌ای است.

در Compose برای Wear OS Material 3، دو HorizontalPagerScaffold و VerticalPagerScaffold طرح‌بندی صفحه‌بند را هماهنگ می‌کنند، به طور خودکار نشانگر صفحه را در موقعیت مناسب قرار می‌دهند و انتقال‌ها را با TimeText مدیریت می‌کنند. هر صفحه در یک AnimatedPage composable قرار می‌گیرد که مقیاس‌بندی، تغییر شکل گوشه‌های گرد و جلوه‌های Scrim را هنگام انتقال صفحات در صفحه نمایش گرد اعمال می‌کند.

انیمیشن زیر نشان می‌دهد که چگونه HorizontalPagerScaffold و AnimatedPage در طول کشیدن افقی، صفحات را مقیاس‌بندی و متحرک می‌کنند:

سلسله مراتب داربست برای صفحه بندی

هنگام طراحی طرح‌بندی‌های صفحه‌بندی‌شده در Material 3 - چه با کشیدن انگشت به چپ یا راست ( HorizontalPager ) و چه با کشیدن انگشت به بالا یا پایین ( VerticalPager ) - از سلسله مراتب کامپوننت زیر از کانتینر بیرونی تا محتوای داخلی استفاده کنید:

  1. AppScaffold : بیرونی‌ترین کانتینر در ریشه برنامه شما (فقط از یکی برای هر برنامه استفاده کنید). این کانتینر، لایه سراسری TimeText را نگه می‌دارد تا ساعت در حین انتقال صفحه و حرکات کشیدن انگشت برای رد کردن، در بالای صفحه ثابت بماند.
  2. HorizontalPagerScaffold یا VerticalPagerScaffold : درون AppScaffold در سطح pager قرار می‌گیرد. این کتابخانه انتقال بین TimeText و HorizontalPageIndicator یا VerticalPageIndicator را هماهنگ می‌کند.
  3. HorizontalPager یا VerticalPager : کانتینر پایه پیجر که حرکات کشیدن انگشت، فیزیک پرتاب کردن و ضربه زدن چرخشی به ورودی را با استفاده از PagerState مشترک مدیریت می‌کند.
  4. AnimatedPage : درون لامبدا محتوای صفحه پیجر قرار می‌گیرد. این عنصر هر صفحه را به صورت جداگانه پوشش می‌دهد تا انیمیشن‌های انتقال Material 3 (افکت‌های مقیاس‌بندی و اسکریم) را بر اساس آفست صفحه در 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، توابع HorizontalPagerScaffold ، HorizontalPager ، AnimatedPage و ScreenScaffold را درون AppScaffold برنامه خود قرار دهید.

از PagerScaffoldDefaults.snapWithSpringFlingBehavior برای flingBehavior استفاده کنید تا فیزیک حرکت فنر Material 3 و snapping صفحه واکنش‌گرا ( HighSnapPositionalThreshold ) اعمال شود. به طور پیش‌فرض، 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 به طور پیش‌فرض قابلیت چرخش صفحه (rotary Pager) را فعال می‌کند ( RotaryScrollableDefaults.snapBehavior(state) ). PagerScaffoldDefaults.snapWithSpringFlingBehavior را به flingBehavior ارسال کنید و هر صفحه را در 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")
                        }
                    }
                }
            }
        }
    }
}

سفارشی‌سازی رفتار پیجر

شما می‌توانید حساسیت snapping در HorizontalPagerScaffold و VerticalPagerScaffold را متناسب با نیازهای تعاملی برنامه خود تنظیم کنید.

تنظیم حساسیت ضربه محکم و ناگهانی برای تمرینات

در طول تمرینات یا فعالیت‌های پر تحرک که کنترل حرکات درشت کاربر محدود است، لمس‌های تصادفی یا چرخش‌های جزئی تاج می‌تواند ناخواسته صفحات را تغییر دهد. برای این صفحات، پیجر خود را با حساسیت ضربه محکم و ناگهانی کم پیکربندی کنید:

  • PagerDefaults.snapFlingBehavior را با maxFlingPages = 0 و snapPositionalThreshold = PagerScaffoldDefaults.LowSnapPositionalThreshold ارسال کنید تا برای چرخاندن صفحه، کشیدن عمدی در قسمت بزرگتری از صفحه نمایش لازم باشد.
  • اگر قابلیت snapping صفحه با چرخش را فعال کرده‌اید، در snapSensitivity = RotaryScrollableDefaults.LowSnapSensitivity RotaryScrollableDefaults.snapBehavior را طوری تنظیم کنید که قبل از snapping به صفحه بعد، چرخش بیشتری لازم باشد.
@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
                    }
                }
            }
        }
    }
}

برای پیاده‌سازی‌های نمونه کامل، به Pager.kt در مخزن android/snippets و PagerScaffoldSample.kt در مخزن AndroidX مراجعه کنید.