หากต้องการพลิกดูเนื้อหาในลักษณะซ้ายและขวาหรือขึ้นและลง คุณสามารถใช้
Composables
HorizontalPager
และ
VerticalPager
ตามลำดับ Composable เหล่านี้มีฟังก์ชันคล้ายกับ
ViewPager
ในระบบ
มุมมอง โดยค่าเริ่มต้น HorizontalPager
จะใช้ความกว้างเต็มของหน้าจอ
VerticalPager
จะใช้ความสูงเต็ม และเครื่องมือเปลี่ยนหน้าจะเลื่อนได้ทีละหน้าเท่านั้น
ค่าเริ่มต้นเหล่านี้กำหนดค่าได้ทั้งหมด
HorizontalPager
หากต้องการสร้าง Pager ที่เลื่อนในแนวนอนไปทางซ้ายและขวา ให้ใช้
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
เป็นค่าที่มากกว่า 0
เลื่อนไปยังรายการในเพจเจอร์
หากต้องการเลื่อนไปยังหน้าหนึ่งๆ ในเครื่องมือเปลี่ยนหน้า ให้สร้างออบเจ็กต์
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
มีพร็อพเพอร์ตี้ 3 รายการที่มีข้อมูลเกี่ยวกับหน้าเว็บ ได้แก่
currentPage
settledPage
และ
targetPage
currentPage
: หน้าเว็บที่ใกล้กับตำแหน่งสแนปมากที่สุด โดยค่าเริ่มต้น position จะอยู่ที่จุดเริ่มต้นของเลย์เอาต์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) ) } }

ใช้เอฟเฟกต์การเลื่อนรายการกับเนื้อหา
กรณีการใช้งานทั่วไปคือการใช้ตำแหน่งการเลื่อนเพื่อใช้เอฟเฟกต์กับรายการ Pager
หากต้องการดูว่าหน้าเว็บอยู่ห่างจากหน้าที่เลือกในปัจจุบันเท่าใด คุณสามารถ
ใช้
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
ด้วย 3 โดยคำนึงถึงระยะห่าง
ระหว่างรายการ
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
ใช้เป็นตัวอย่างที่นี่เท่านั้น คุณตั้งค่ามิติข้อมูลระยะห่างจากขอบแต่ละรายการเป็นค่าใดก็ได้
ปรับแต่งลักษณะการทำงานของการเลื่อน
Composable HorizontalPager
และ VerticalPager
เริ่มต้นจะระบุวิธีที่ท่าทางการเลื่อนทำงานร่วมกับ Pager อย่างไรก็ตาม คุณสามารถปรับแต่งและเปลี่ยนค่าเริ่มต้น เช่น pagerSnapDistance
หรือ flingBehavior
ได้
ระยะการสแนป
โดยค่าเริ่มต้น HorizontalPager
และ VerticalPager
จะกำหนดจำนวนหน้าสูงสุดที่ท่าทางปัดสามารถเลื่อนผ่านได้เป็นครั้งละ 1 หน้า หากต้องการเปลี่ยน
การตั้งค่านี้ ให้ตั้งค่า
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) } }
สร้างเพจเจอร์ที่เลื่อนอัตโนมัติ
ส่วนนี้จะอธิบายวิธีสร้าง Pager ที่เลื่อนอัตโนมัติพร้อมตัวระบุหน้าใน 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
จะเลื่อนเพจเจอร์โดยอัตโนมัติทุกๆ 2 วินาที เว้นแต่ผู้ใช้จะลากเพจเจอร์หรือกดหน้าใดหน้าหนึ่งHorizontalPager
จะแสดงรายการหน้าเว็บ โดยแต่ละหน้าจะมีText
composable แสดงหมายเลขหน้า ตัวแก้ไขจะเติมหน้าเว็บ ตั้งค่าสีพื้นหลัง จาก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
ที่ใช้ร่วมกันได้เป็นองค์ประกอบรูท- ภายใน
Box
คอมโพสฟังก์ชันRow
จะจัดเรียงตัวบ่งชี้หน้าในแนวนอน
- ภายใน
- ตัวบ่งหน้าเว็บที่กำหนดเองจะแสดงเป็นแถวของวงกลม โดยแต่ละวงกลมที่
Box
ตัดกับcircle
จะแสดงหน้าเว็บ - วงกลมของหน้าปัจจุบันจะมีสีเป็น
DarkGray
ส่วนวงกลมอื่นๆ จะเป็นLightGray
พารามิเตอร์currentPageIndex
จะกำหนดวงกลมที่แสดงเป็นสีเทาเข้ม
ผลลัพธ์
วิดีโอนี้แสดงเครื่องมือเปลี่ยนหน้าอัตโนมัติพื้นฐานจากข้อมูลโค้ดก่อนหน้า