A modifier which connects rotary events with scrollable containers such as Column, LazyList and others.
@Composable
fun RotaryScrollSample() {
val scrollableState = rememberLazyListState()
val focusRequester = remember { FocusRequester() }
LazyColumn(
modifier =
Modifier.fillMaxSize()
.requestFocusOnHierarchyActive()
.rotaryScrollable(
behavior = RotaryScrollableDefaults.behavior(scrollableState),
focusRequester = focusRequester,
),
horizontalAlignment = Alignment.CenterHorizontally,
state = scrollableState,
) {
items(300) {
BasicText(
text = "item $it",
modifier = Modifier.background(Color.Gray),
style = TextStyle.Default.copy(),
)
}
}
}
@Composable
fun RotaryScrollWithOverscrollSample() {
val scrollableState = rememberScrollState()
val focusRequester = remember { FocusRequester() }
val overscrollEffect = rememberOverscrollEffect()
val screenHeightDp = LocalConfiguration.current.screenHeightDp.dp
Column(
Modifier.fillMaxSize()
.requestFocusOnHierarchyActive()
.rotaryScrollable(
behavior = RotaryScrollableDefaults.behavior(scrollableState),
focusRequester = focusRequester,
overscrollEffect = overscrollEffect,
)
.verticalScroll(scrollableState, overscrollEffect)
.overscroll(overscrollEffect),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text("Top")
Spacer(modifier = Modifier.height(screenHeightDp / 2))
Text("Scroll this list up and down with rotary input", textAlign = TextAlign.Center)
Spacer(modifier = Modifier.height(screenHeightDp / 2))
Text("Bottom")
}
}
RotarySnapSample
@Composable
fun RotarySnapSample() {
val scrollableState = rememberLazyListState()
val focusRequester = remember { FocusRequester() }
LazyColumn(
modifier =
Modifier.fillMaxSize()
.requestFocusOnHierarchyActive()
.rotaryScrollable(
behavior =
RotaryScrollableDefaults.snapBehavior(
scrollableState,
// This sample has a custom implementation of
// RotarySnapLayoutInfoProvider which is required for snapping behavior.
// ScalingLazyColumn has it built-in, so it's not required there.
remember(scrollableState) {
object : RotarySnapLayoutInfoProvider {
override val averageItemSize: Float
get() {
val items = scrollableState.layoutInfo.visibleItemsInfo
return (items.fastSumBy { it.size } / items.size)
.toFloat()
}
override val currentItemIndex: Int
get() = scrollableState.firstVisibleItemIndex
override val currentItemOffset: Float
get() =
scrollableState.firstVisibleItemScrollOffset.toFloat()
override val totalItemCount: Int
get() = scrollableState.layoutInfo.totalItemsCount
}
},
),
focusRequester = focusRequester,
),
horizontalAlignment = Alignment.CenterHorizontally,
state = scrollableState,
) {
items(300) {
BasicText(text = "item $it", modifier = Modifier.background(Color.Gray).height(50.dp))
}
}
}