برای ورق زدن محتوا بهصورت افقی یا عمودی، میتوانید از عناصر ترکیبی
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 }
میتوانید مقادیر top و bottom را تنظیم کنید تا جلوههای مشابهی برای
VerticalPager بهدست آورید. مقدار 32.dp فقط در اینجا بهعنوان مثال استفاده میشود؛ میتوانید
هریک از ابعاد حاشیهگذاری را روی هر مقداری تنظیم کنید.
سفارشیسازی رفتار پیمایش
ترکیبپذیرهای پیشفرض HorizontalPager و VerticalPager مشخص میکنند
اشارههای پیمایش چگونه با صفحهگرد کار میکنند. بااینحال، میتوانید پیشفرضها مثل pagerSnapDistance یا flingBehavior را سفارشیسازی و تغییر دهید.
فاصله چفت کردن
بهطور پیشفرض، HorizontalPager و VerticalPager حداکثر تعداد صفحههایی را که
اشاره پرتاب میتواند از آنها عبور کند روی یک صفحه در هر بار تنظیم میکنند. برای تغییر دادن
این تنظیم، pagerSnapDistance را در flingBehavior تنظیم کنید:
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فهرستی از صفحات را نمایش میدهد که هرکدامTextcomposable دارد که شماره صفحه را نمایش میدهد. اصلاحگر صفحه را پر میکند، رنگ پسزمینه را از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تعیین میکند کدام دایره به رنگ خاکستری تیره رندر شود.
نتیجه
این ویدیو صفحهگردان پیشرونده خودکار پایه را از گزیدههای قبلی نمایش میدهد: