Ahmed Mourad
04/25/2021, 5:05 PM@Composable
fun SomeRangeBar(
lower: Float,
upper: Float,
onLowerChanged: (Float) -> Unit,
onUpperChanged: (Float) -> Unit,
range: ClosedRange<Float>,
modifier: Modifier = Modifier
) {
Canvas(modifier = modifier.pointerInput(Unit) {
detectHorizontalDragGestures {
if (headToMove == Head.LOWER) {
onLowerChanged(
newValue.coerceIn(range.start, upper)
)
} else {
onUpperChanged(
newValue.coerceIn(lower, range.endInclusive)
)
}
}
}) {
// drawing...
}
}
@Composable
fun UseSomeRangeBar() {
val lower by remember { mutableStateOf(25f) }
val upper by remember { mutableStateOf(100f) }
SomeRangeBar(
lower = lower,
upper = upper,
onLowerChanged = { lower = it },
onUpperChanged = { upper = it },
)
}
The problem would be that, since the pointerInput
closure survives recomposition and since it also captures the values of lower
and upper
then the values of lower
and upper
passed to coerceIn
are always the initial lower and upper values, all subsequent values of lower
and upper
never make it to the lambda.
A simple solution to this is to pass MutableState<Float>
instead of Float
as lower
and upper
and since MutableState
is mutable lol, then updates to lower
and upper
make it to the closure:
@Composable
fun SomeRangeBar(
lower: State<Float>,
upper: State<Float>,
//...
) {
//...
}
@Composable
fun UseSomeRangeBar() {
val lower = remember { mutableStateOf(25f) }
val upper = remember { mutableStateOf(100f) }
SomeRangeBar(
lower = lower,
upper = upper,
onLowerChanged = { lower.value = it },
onUpperChanged = { upper.value = it },
)
}
But I haven't seen anything like this in the available composables, what's the convention in such a situation?Dominaezzz
04/25/2021, 5:30 PMrememberUpdatableState
which is built for this I think.Dominaezzz
04/25/2021, 5:31 PMDominaezzz
04/25/2021, 5:31 PMAhmed Mourad
04/25/2021, 6:02 PMrememberUpdatedState
seems to do the trick, Thank you!
pointerInput
uses LaunchedEffect
which I believe create a coroutine which is only restarted when the key passed is changed, so although being counterintuitive I believe it is the desired behavior.
I tried passing a random UUID as a key and it started doing some weird shenanigans, the dragging was forcibly ended on each recomposition.
Also, sorry about the large snippet thing.Dominaezzz
04/25/2021, 6:05 PMmodifier.pointerInput(lower, upper)
?Ahmed Mourad
04/25/2021, 6:17 PMupper
and lower
are constantly updated while the dragging is happening, not just when it ends, and since their values changing is what causes recomposition, it would be similar to passing a UUID as a key, where the dragging is forcibly ended on the first update to either of them.Ahmed Mourad
04/25/2021, 6:17 PMDominaezzz
04/25/2021, 6:20 PM