在元素的內容邊界超過尺寸上限時,使用 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,或 LazyColumn 等可組合項,用於標準捲動清單。這些高階元件在常見用途中較為簡單,且本身是使用 scrollableArea 建構而成。
scrollableArea 和 scrollable 修飾符的差異
scrollableArea 和 scrollable 的主要差異在於解讀使用者捲動手勢的方式:
scrollable(原始差異):差異會直接反映使用者在螢幕上輸入內容 (例如拖曳指標) 的實際動作。scrollableArea(內容導向差異):delta在語意上會反轉,代表捲動位置的所選變更,讓內容看起來會隨著使用者的手勢移動,這通常與指標移動相反。
您可以這樣想:scrollable 會告訴您指標如何移動,而 scrollableArea 則會將指標移動轉譯為內容在一般可捲動檢視畫面中的移動方式。這種反轉效果,正是實作標準可捲動容器時,scrollableArea 感覺更自然的原因。
下表彙整了常見情境的差異符號:
使用者手勢 |
|
|
|---|---|---|
游標向上移動 |
負面 |
正面 |
游標向下移動 |
正面 |
負面 |
游標向左移動 |
負面 |
正值 (由右至左語言為負值) |
游標向右移動 |
正面 |
負值 (由右至左語言為正值) |
(*) scrollableArea 差異符號注意事項:scrollableArea 的差異符號不只是單純的反轉。這項功能會智慧考量:
- 方向:直向或橫向。
LayoutDirection:LTR 或 RTL (對於水平捲動特別重要)。reverseScrolling旗標:捲動方向是否反向。
除了反轉捲動差異之外,scrollableArea 也會將內容裁剪至版面配置的邊界,並處理過度捲動效果的算繪。根據預設,系統會使用 LocalOverscrollFactory 提供的效果。您可以使用接受 OverscrollEffect 參數的 scrollableArea 超載,自訂或停用這項功能。
scrollableArea 修飾符的使用時機
如需建構自訂捲動元件,但 horizontalScroll 或 verticalScroll 修飾符或 Lazy 版面配置無法充分提供服務,則應使用 scrollableArea 修飾符。這通常涉及以下情況:
- 自訂版面配置邏輯:項目排列方式會根據捲動位置動態變更。
- 獨特的視覺效果:在捲動時對子項套用轉換、縮放或其他效果。
- 直接控制:需要精細控制捲動機制,超出
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 修飾符和捲動修飾符不同,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 - 在 Compose 中使用 View