ตัวแก้ไข verticalScroll และ horizontalScroll เป็นวิธีที่ง่ายที่สุดในการอนุญาตให้ผู้ใช้เลื่อนองค์ประกอบเมื่อขอบเขตของเนื้อหามีขนาดใหญ่กว่าข้อจำกัดขนาดสูงสุด เมื่อใช้ตัวแก้ไข verticalScroll และ horizontalScroll คุณไม่จำเป็นต้องแปลหรือออฟเซ็ตเนื้อหา
@Composable private fun ScrollBoxes() { Column( modifier = Modifier .background(Color.LightGray) .size(100.dp) .verticalScroll(rememberScrollState()) ) { repeat(10) { Text("Item $it", modifier = Modifier.padding(2.dp)) } } }
ScrollState ช่วยให้คุณเปลี่ยนตำแหน่งการเลื่อนหรือดูสถานะปัจจุบันได้ หากต้องการสร้างด้วยพารามิเตอร์เริ่มต้น ให้ใช้ rememberScrollState()
@Composable private fun ScrollBoxesSmooth() { // Smoothly scroll 100px on first composition val state = rememberScrollState() LaunchedEffect(Unit) { state.animateScrollTo(100) } Column( modifier = Modifier .background(Color.LightGray) .size(100.dp) .padding(horizontal = 8.dp) .verticalScroll(state) ) { repeat(10) { Text("Item $it", modifier = Modifier.padding(2.dp)) } } }
ตัวแก้ไขพื้นที่ที่เลื่อนได้
ตัวแก้ไข scrollableArea เป็นองค์ประกอบพื้นฐานสำหรับการสร้างคอนเทนเนอร์ที่เลื่อนได้ที่กำหนดเอง ซึ่งให้การแยกข้อมูลระดับสูงกว่าตัวแก้ไข scrollable โดยจัดการข้อกำหนดทั่วไป เช่น การตีความเดลต้าของท่าทางสัมผัส การตัดเนื้อหา และเอฟเฟกต์การเลื่อนเกิน
แม้ว่า scrollableArea จะใช้สำหรับการติดตั้งใช้งานที่กำหนดเอง แต่โดยทั่วไปคุณควรเลือกใช้โซลูชันสำเร็จรูป เช่น verticalScroll, horizontalScroll หรือ Composable เช่น LazyColumn สำหรับรายการแบบเลื่อนมาตรฐาน คอมโพเนนต์ระดับสูงเหล่านี้จะใช้งานง่ายกว่าสำหรับกรณีการใช้งานทั่วไป และสร้างขึ้นโดยใช้ scrollableArea
ความแตกต่างระหว่างตัวแก้ไข scrollableArea และ scrollable
ความแตกต่างหลักระหว่าง scrollableArea และ scrollable อยู่ที่วิธีตีความท่าทางการเลื่อนของผู้ใช้ ดังนี้
scrollable(เดลตาดิบ): เดลตาจะแสดงการเคลื่อนไหวทางกายภาพของอินพุตของผู้ใช้ (เช่น การลากเคอร์เซอร์) บนหน้าจอโดยตรงscrollableArea(เดลต้าที่เน้นเนื้อหา):deltaจะกลับด้านตามความหมายเพื่อแสดงการเปลี่ยนแปลงที่เลือกในตำแหน่งการเลื่อนเพื่อให้เนื้อหาปรากฏขึ้นเพื่อเลื่อนตามท่าทางสัมผัสของผู้ใช้ ซึ่งมักจะตรงข้ามกับการเคลื่อนไหวของเคอร์เซอร์
ลองนึกภาพตามนี้ scrollable จะบอกคุณว่าตัวชี้เคลื่อนที่อย่างไร ส่วน scrollableArea จะแปลการเคลื่อนไหวของตัวชี้นั้นเป็นวิธีที่เนื้อหาควรเคลื่อนที่ภายในมุมมองที่เลื่อนได้ทั่วไป การกลับด้านนี้เป็นสาเหตุที่ทำให้ scrollableArea รู้สึกเป็นธรรมชาติมากขึ้นเมื่อใช้คอนเทนเนอร์แบบเลื่อนได้มาตรฐาน
ตารางต่อไปนี้จะสรุปเครื่องหมายเดลต้าสำหรับสถานการณ์ที่พบบ่อย
ท่าทางผู้ใช้ |
delta รายงานต่อ |
delta รายงานไปยัง |
|---|---|---|
ตัวชี้เลื่อนขึ้น |
เชิงลบ |
เชิงบวก |
ตัวชี้เลื่อนลง |
เชิงบวก |
เชิงลบ |
ตัวชี้เลื่อนไปทางซ้าย |
เชิงลบ |
บวก (ลบสำหรับ RTL) |
ตัวชี้เลื่อนไปทางขวา |
เชิงบวก |
ลบ (บวกสำหรับ RTL) |
(*) หมายเหตุเกี่ยวกับเครื่องหมายเดลต้าของ scrollableArea: เครื่องหมายเดลต้าจาก scrollableArea ไม่ใช่แค่การผกผันแบบธรรมดา โดยจะพิจารณาปัจจัยต่อไปนี้อย่างชาญฉลาด
- การวางแนว: แนวตั้งหรือแนวนอน
LayoutDirection: LTR หรือ RTL (สำคัญอย่างยิ่งสำหรับการเลื่อนแนวนอน)- แฟล็ก
reverseScrolling: การกลับทิศทางการเลื่อนหรือไม่
นอกจากการกลับค่าเดลต้าของการเลื่อนแล้ว scrollableArea ยังตัดเนื้อหาให้อยู่ในขอบเขตของเลย์เอาต์และจัดการการแสดงผลของเอฟเฟกต์การเลื่อนเกินด้วย โดยค่าเริ่มต้น ระบบจะใช้เอฟเฟกต์ที่ LocalOverscrollFactory มีให้
คุณสามารถปรับแต่งหรือปิดใช้ฟีเจอร์นี้ได้โดยใช้โอเวอร์โหลด scrollableArea ที่ยอมรับพารามิเตอร์ OverscrollEffect
กรณีที่ควรใช้ตัวแก้ไข scrollableArea
คุณควรใช้ตัวแก้ไข scrollableArea เมื่อต้องการสร้างคอมโพเนนต์การเลื่อนที่กำหนดเองซึ่งตัวแก้ไข horizontalScroll หรือ verticalScroll หรือเลย์เอาต์ Lazy ไม่สามารถรองรับได้อย่างเพียงพอ ซึ่งมักเกี่ยวข้องกับกรณีที่มีลักษณะต่อไปนี้
- ตรรกะเลย์เอาต์ที่กำหนดเอง: เมื่อการจัดเรียงรายการเปลี่ยนแปลงแบบไดนามิกตามตำแหน่งการเลื่อน
- เอฟเฟกต์ภาพที่ไม่ซ้ำกัน: การใช้การเปลี่ยนรูปแบบ การปรับขนาด หรือเอฟเฟกต์อื่นๆ กับองค์ประกอบย่อยขณะที่ผู้ใช้เลื่อนดู
- การควบคุมโดยตรง: ต้องการการควบคุมกลไกการเลื่อนอย่างละเอียดนอกเหนือจากที่
verticalScrollหรือเลย์เอาต์แบบ Lazy แสดง
สร้างรายการแบบวงล้อที่กำหนดเองโดยใช้ scrollableArea
ตัวอย่างต่อไปนี้แสดงการใช้ scrollableArea เพื่อสร้างรายการแนวตั้งที่กำหนดเองซึ่งรายการจะลดขนาดลงเมื่อเคลื่อนออกจากจุดศูนย์กลาง ทำให้เกิดเอฟเฟกต์ภาพ "คล้ายวงล้อ" การเปลี่ยนรูปแบบที่ขึ้นอยู่กับการเลื่อนประเภทนี้เป็นกรณีการใช้งานที่เหมาะอย่างยิ่งสำหรับ scrollableArea
scrollableArea
@Composable private fun ScrollableAreaSample() { // ... Layout( modifier = Modifier .size(150.dp) .scrollableArea(scrollState, Orientation.Vertical) .background(Color.LightGray), // ... ) { measurables, constraints -> // ... // Update the maximum scroll value to not scroll beyond limits and stop when scroll // reaches the end. scrollState.maxValue = (totalHeight - viewportHeight).coerceAtLeast(0) // Position the children within the layout. layout(constraints.maxWidth, viewportHeight) { // The current vertical scroll position, in pixels. val scrollY = scrollState.value val viewportCenterY = scrollY + viewportHeight / 2 var placeableLayoutPositionY = 0 placeables.forEach { placeable -> // This sample applies a scaling effect to items based on their distance // from the center, creating a wheel-like effect. // ... // Place the item horizontally centered with a layer transformation for // scaling to achieve wheel-like effect. placeable.placeRelativeWithLayer( x = constraints.maxWidth / 2 - placeable.width / 2, // Offset y by the scroll position to make placeable visible in the viewport. y = placeableLayoutPositionY - scrollY, ) { scaleX = scaleFactor scaleY = scaleFactor } // Move to the next item's vertical position. placeableLayoutPositionY += placeable.height } } } } // ...
ตัวแก้ไขที่เลื่อนได้
ตัวปรับแต่ง scrollable แตกต่างจากตัวปรับแต่งการเลื่อนตรงที่ scrollable จะตรวจจับท่าทางการเลื่อนและบันทึกเดลต้า แต่จะไม่ชดเชยเนื้อหาโดยอัตโนมัติ แต่จะมอบสิทธิ์นี้ให้กับผู้ใช้ผ่าน ScrollableState แทน ซึ่งจำเป็นเพื่อให้ตัวแก้ไขนี้ทำงานได้อย่างถูกต้อง
เมื่อสร้าง ScrollableState คุณต้องระบุฟังก์ชัน consumeScrollDelta ซึ่งจะเรียกใช้ในแต่ละขั้นตอนการเลื่อน (โดยการป้อนข้อมูลด้วยท่าทางสัมผัส การเลื่อนอย่างราบรื่น หรือการเลื่อนอย่างรวดเร็ว) โดยมีเดลต้าเป็นพิกเซล ฟังก์ชันนี้ต้องแสดงผลระยะทางในการเลื่อนที่ใช้ไป เพื่อให้แน่ใจว่าเหตุการณ์ได้รับการเผยแพร่อย่างถูกต้องในกรณีที่มีองค์ประกอบที่ฝังอยู่ซึ่งมีตัวแก้ไข scrollable
ข้อมูลโค้ดต่อไปนี้จะตรวจจับท่าทางสัมผัสและแสดงค่าตัวเลขสำหรับออฟเซ็ต แต่ไม่ได้ออฟเซ็ตองค์ประกอบใดๆ
@Composable private fun ScrollableSample() { // actual composable state var offset by remember { mutableFloatStateOf(0f) } Box( Modifier .size(150.dp) .scrollable( orientation = Orientation.Vertical, // Scrollable state: describes how to consume // scrolling delta and update offset state = rememberScrollableState { delta -> offset += delta delta } ) .background(Color.LightGray), contentAlignment = Alignment.Center ) { Text(offset.toString()) } }
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- ทำความเข้าใจท่าทางสัมผัส
- ย้ายข้อมูล
CoordinatorLayoutไปยัง Compose - การใช้ View ใน Compose