Skip to content

Instantly share code, notes, and snippets.

@odecaux
Last active June 30, 2020 14:39
Show Gist options
  • Save odecaux/808c71b646c0a170cfeb2cb0686858e0 to your computer and use it in GitHub Desktop.
Save odecaux/808c71b646c0a170cfeb2cb0686858e0 to your computer and use it in GitHub Desktop.
@Composable
fun HorizontalSliderWithAnchor(
modifier : Modifier = Modifier,
children: @Composable() () -> Unit
) {
var childPositions by state { listOf<ChildPosition>()}
WithConstraints() {
val boxWidth = with(DensityAmbient.current) { constraints.maxWidth.toDp() }
//setting up all the anchors.
//if childPositions is empty (first pass), anchors are empty, and the scroll range is 0f->0f
val leftBoundPx : Px = -(childPositions.lastOrNull()?.left?.toPx() ?: 0.px)
val rightBoundPx = 0.px
val flingConfig = AnchorsFlingConfig( childPositions.map { -it.left.toPx().value} )
val scrollPosition = animatedFloat(0f)
scrollPosition.setBounds(leftBoundPx.value, rightBoundPx.value)
val xOffset = with(DensityAmbient.current) { scrollPosition.value.toDp() }
Surface(modifier = modifier
.draggable(
startDragImmediately = scrollPosition.isRunning,
dragDirection = DragDirection.Horizontal,
onDragStopped = { scrollPosition.fling(flingConfig, it) })
{ delta ->
scrollPosition.snapTo(scrollPosition.value + delta)
delta
}
.width(boxWidth)
) {
Layout(children, modifier
.clipToBounds()
.offset(x = xOffset)) { measurables, constraints, _ ->
//unsure what I'm doing here, seems to allow children to use .fillMaxWidth()
val childConstraints = constraints.copy(minWidth = IntPx.Zero)
val newTabPositions = mutableListOf<ChildPosition>()
var fixedSpace = IntPx.Zero
var crossAxisSpace = IntPx.Zero
//measuring and storing the positions
val placeables = measurables.map{child ->
val placeable = child.measure(childConstraints)
newTabPositions.add(ChildPosition(
left = fixedSpace,
width = placeable.width))
fixedSpace += placeable.width
crossAxisSpace = max(crossAxisSpace, placeable.height)
placeable
}
//transfering positions, recomposing ?
if (childPositions != newTabPositions) {
childPositions = newTabPositions
}
val width = min(fixedSpace, constraints.maxWidth)
val height = min(crossAxisSpace, constraints.maxHeight)
//placing as a limitless row
layout(width , height) {
var position = 0.ipx
placeables.forEach {
it.place(position, 0.ipx)
position += it.width
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment