james
06/27/2022, 4:24 AMChris Sinco [G]
06/27/2022, 2:18 PMjames
06/27/2022, 10:34 PMDefaultFlingBehavior()
from Scrollable.kt.. I simply created my own copy of it and I added a parameter which can be updated from within:
fun velocityTrackingFlingBehavior(currentFlingVelocity: MutableState<Float>): FlingBehavior
then where I declare my LazyColumn, I keep the state hoisted above it, something like:
val currentFlingVelocity = remember { mutableStateOf(0f) }
LazyColumn(
...
flingBehavior = velocityTrackingFlingBehavior(currentFlingVelocity)
...
)
I should add: my reason for doing all of this is I want to use the velocity as a modifier to some behaviour within individual LazyColumn items
now I think my next step will be to derive some state from that currentFlingVelocity to debounce and normalise it into values within a small group of ranges, and pass that derived state into my LazyColumn items.. does that sound about right in terms of reducing the impact to performance?james
07/04/2022, 10:45 PMChris Sinco [G]
07/06/2022, 7:25 PMBen Trengrove [G]
07/07/2022, 1:08 AMMyFlingBehaviour(flingDecay, animationState)
. I have no idea if this would work, but that would be what I would have tried first if I was trying to do thisjames
07/07/2022, 1:15 AMMyFlingBehaviour(flingDecay, animationState)
would be that the fling behaviour is on the LazyColumn itself, whereas the animationState
lives inside individual `item`s, so there are many animation states (which are lazily created as items come into scope)Ben Trengrove [G]
07/07/2022, 1:40 AM@Composable
private fun rememberMyFlingBehavior(): MyFlingBehavior {
val flingSpec = rememberSplineBasedDecay<Float>()
return remember(flingSpec) {
MyFlingBehavior(flingSpec)
}
}
private class MyFlingBehavior(
private val flingDecay: DecayAnimationSpec<Float>
) : FlingBehavior {
private var _lastValue = mutableStateOf(0f)
val lastValue: State<Float> = _lastValue
override suspend fun ScrollScope.performFling(initialVelocity: Float): Float {
// come up with the better threshold, but we need it since spline curve gives us NaNs
return if (abs(initialVelocity) > 1f) {
var velocityLeft = initialVelocity
_lastValue.value = 0f
AnimationState(
initialValue = 0f,
initialVelocity = initialVelocity,
).animateDecay(flingDecay) {
val delta = value - lastValue.value
val consumed = scrollBy(delta)
_lastValue.value = value
velocityLeft = this.velocity
// avoid rounding errors and stop if anything is unconsumed
if (abs(delta - consumed) > 0.5f) this.cancelAnimation()
}
velocityLeft
} else {
initialVelocity
}
}
}
val fling = rememberMyFlingBehavior()
println("Fling: ${fling.lastValue.value}")
LazyColumn(
contentPadding = padding,
flingBehavior = fling
)
Ben Trengrove [G]
07/07/2022, 1:41 AMBen Trengrove [G]
07/07/2022, 1:57 AMitemsIndexed(friends) { index, friend ->
Friend(
friend = friend,
onFriendClick = onFriendClick,
modifier = Modifier
.padding(horizontal = 16.dp, vertical = 4.dp)
.animateEnterExit(
enter = slideInVertically(
animationSpec = spring(...)
) { it * (index + 1) } // staggered entrance
)
)
}
james
07/07/2022, 3:36 AMFlingBehavior
is an improved version of mine! at the very least I will stop passing in the mutable state as a parameter and just expose it, as you’ve shownjames
07/07/2022, 3:42 AMjames
07/07/2022, 3:51 AMcurrentFlingVelocity
which I’m now tracking, and does this:
val normalizedVelocity by remember {
derivedStateOf {
normalizeVelocity(currentFlingVelocity.value)
}
}
my normalizedVelocity()
function does some calculations and ensures it will only ever return one of 6 possible values (so there’s 6 condensed “scroll speeds”)
now, I pass the normalizedVelocity
value down into each item
(remembering this is still performant because I’ve used derivedStateOf), and then where I have my fade in animation, I provide the following animationSpec:
animationSpec = tween(velocityBasedFadeInDuration(normalizedScrollVelocity))
that velocityBasedFadeInDuration()
function simply returns a particular value in millis, depending on the normalized velocity that was passed in.. so you get 6 possible fade in durations, which change depending on how fast or slow you scrolljames
07/07/2022, 3:52 AMjames
07/07/2022, 3:56 AMnormalizedScrollVelocity
, instead of passing normalizedScrollVelocity
down and causing re-compositionjames
07/07/2022, 3:59 AMBen Trengrove [G]
07/07/2022, 4:04 AMjames
07/07/2022, 11:17 PM