برای ورق زدن محتوا بهصورت افقی یا عمودی، میتوانید از
ترکیبپذیرهای 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 بهصورت تنبل ترکیببندی میشوند
و درصورت نیاز چیدمان میشوند. وقتی کاربر در صفحهها پیمایش میکند، composable
هر صفحهای را که دیگر لازم نیست برمیدارد.
بار کردن صفحههای بیشتر در خارج از صفحه
بهطور پیشفرض، ورقزن فقط صفحههای قابلمشاهده روی صفحه را بار میکند. برای بار کردن صفحههای بیشتر
خارج از صفحه، 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 استفاده کنید. سپس میتوانید جلوههای تغییر شکل را براساس فاصله از صفحه انتخابشده روی محتوایتان اعمال کنید.
برای مثال، برای تنظیم کردن میزان کدر بودن موارد براساس فاصله آنها از مرکز،
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فهرستی از صفحهها را نمایش میدهد که هرکدام دارای یک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تعیین میکند کدام دایره بهرنگ خاکستری تیره نمایش داده شود.
نتیجه
This video displays the basic auto-advancing pager from the preceding snippets: