Tony Kazanjian
03/02/2021, 5:22 PMScrollableState
to a modifier that also includes a DraggableState
has no effect (also, seems like whichever modifier comes next pretty much overwrites the previous one). Code in threadval scrollable = rememberScrollableState {dy ->
Log.d(TAG, "Scrolled to : $dy")
dy
}
LaunchedEffect(state) {
delay(2000)
scrollable.animateScrollBy(1080f)
}
Then, I'm adding the scrollable to the whole layout modifier
Layout(
content = {
val minPage = (state.currentPage - offscreenLimit).coerceAtLeast(state.minPage)
val maxPage = (state.currentPage + offscreenLimit).coerceAtMost(state.maxPage)
for (page in minPage..maxPage) {
val pageData = PageData(page)
val scope = PagerScope(state, page)
key(pageData) {
Box(contentAlignment = Alignment.Center, modifier = pageData) {
scope.pageContent()
}
}
}
},
modifier = modifier.draggable(
orientation = Orientation.Horizontal,
onDragStarted = {
state.selectionState = PagerState.SelectionState.Undecided
},
onDragStopped = { velocity ->
coroutineScope.launch {
// Velocity is in pixels per second, but we deal in percentage offsets, so we
// need to scale the velocity to match
state.fling(velocity / pageSize)
}
},
state = rememberDraggableState { dy ->
coroutineScope.launch {
with(state) {
val pos = pageSize * currentPageOffset
val max = if (currentPage == minPage) 0 else pageSize * offscreenLimit
val min = if (currentPage == maxPage) 0 else -pageSize * offscreenLimit
val newPos = (pos + dy).coerceIn(min.toFloat(), max.toFloat())
snapToOffset(newPos / pageSize)
}
}
},
).scrollable(scrollable, Orientation.Horizontal)
) { measurables, constraints ->
layout(constraints.maxWidth, constraints.maxHeight) {
val currentPage = state.currentPage
val offset = state.currentPageOffset
val childConstraints = constraints.copy(minWidth = 0, minHeight = 0)
measurables
.map {
it.measure(childConstraints) to it.page
}
.forEach { (placeable, page) ->
// TODO: current this centers each page. We should investigate reading
// gravity modifiers on the child, or maybe as a param to Pager.
val xCenterOffset = (constraints.maxWidth - placeable.width) / 2
val yCenterOffset = (constraints.maxHeight - placeable.height) / 2
if (currentPage == page) {
pageSize = placeable.width
}
val xItemOffset = ((page + offset - currentPage) * placeable.width).roundToInt()
placeable.place(
x = xCenterOffset + xItemOffset,
y = yCenterOffset
)
}
}
}
I'm not sure if I have to do anything in the rememberScrollableState
lambda to ensure the composable gets scrolled (it gets fired when I drag, but nothing happens onscreen). It does not take a suspend function so I can't do the same thing as the draggableState does with the animatable offset, etc.
Is there any way I can scroll this thing without the draggable modifier?