How can I achieve snapping like behavior in LazyRow? is there any built-in method to do that?
s
How can I achieve snapping like behavior in LazyRow? is there any built-in method to do that?
3
v
I also need ViewPager-like snapping behavior in my LazyRows but getting there very slowly, so I can only put some thougths here, maybe this would be helpful to someone. I believe
FlingConfig
is meant for snapping in Compose, and there's flingConfig in
LazyListState
that's used by LazyRow. So we can slightly modify
rememberLazyListState
to use custom filngConfig:
Copy code
@Composable
fun rememberFlingLazyListState(
    initialFirstVisibleItemIndex: Int = 0,
    initialFirstVisibleItemScrollOffset: Int = 0,
    interactionState: InteractionState? = null,
    config: FlingConfig = defaultFlingConfig()
): LazyListState {
    val clock = AmbientAnimationClock.current.asDisposableClock()

    // Avoid creating a new instance every invocation
    val saver = remember(config, clock, interactionState) {
        LazyListState.Saver(config, clock, interactionState)
    }

    return rememberSavedInstanceState(config, clock, interactionState, saver = saver) {
        LazyListState(
            initialFirstVisibleItemIndex,
            initialFirstVisibleItemScrollOffset,
            interactionState,
            config,
            clock
        )
    }
}
so it can be used in LazyRow like this:
Copy code
val badgeListScroll = rememberFlingLazyListState(
    config = FlingConfig(
        anchors = pageOffsetList, // list of X-coordinates which will be snapped at while scrolling
        animationSpec = TweenSpec(),
        decayAnimation = FloatExponentialDecaySpec(frictionMultiplier = 1f)
    )
)

LazyRow(
    modifier = Modifier.fillMaxWidth(),
    state = badgeListScroll
) {
	itemsIndexed(badgeList) { index, item -> MyBadge(item) }
}
The problem here is to choose correct value for
decayAnimation
.
FloatExponentialDecaySpec
doesn't allow to set the end coordinate of animation so, after user swipes, scrolling just stops at a 'random' place (depending only on velocity of swipe gesture). Couple of alphas ago, there wasn't any
decay
in
FlingConfig
and snapping worked almost fine with similar config...
d
The anchors in the
FlingConfig
in your snippet should give you the snapping behavior. If not, please file a bug. 🙂
decayAnimation
describes what the natural slow-down should look like. It is also used to calculate where the natural target point is, in order to choose a snapping target from the given list of
anchors
. If/when you have
anchors
defined, the
animationSpec
is used for the snapping animation. I would suggest having a spring animation for the snapping (instead of tween) to maintain continuity in velocity. If you need a "snappier" animation, you could consider increasing the spring stiffness.
v
@Doris Liu thank you for your clarifications. Maybe what I want is completely different behaviour and is not snapping: I want LazyRow, after user gesture, to stop (accelerating itself if needed) exactly at one of the anchor points. So it would behave like horizontal app icon lists in Play Store app. With this flingConfig, if I just touch, pan and then release LazyRow, (so start velocity is 0), it just stops - there's no scrolling to the nearest anchor.
d
So with the
LazyRow
you never want it to come to a stop in-between two items after a gesture (be it panning or flinging). That makes sense. Thanks for clarifying.👍 Looks like that work is already tracked here: https://issuetracker.google.com/issues/166590434 Please feel free to cc yourself to get updates from the work, and/or add additional clarification/request in the tracker. 🙂
🙌 2
269 Views