Michal Klimczak
04/25/2021, 2:36 PMLaunchedEffect
or am I abusing something? I'm trying to detect changes to multiple States
and make a callback out of them.
@Composable
fun FooSlider(
onStartedSelection: () -> Unit,
onSelected: (value: Float) -> Unit
) {
var sliderPosition by remember { mutableStateOf(0f) }
val sliderInteractions = remember { MutableInteractionSource() }
val isDragged by sliderInteractions.collectIsDraggedAsState()
val isPressed by sliderInteractions.collectIsPressedAsState()
LaunchedEffect(isDragged || isPressed) {
when {
isDragged || isPressed -> onStartedSelection()
else -> onSelected(sliderPosition)
}
}
Slider(
value = sliderPosition,
onValueChange = { sliderPosition = it },
interactionSource = sliderInteractions
)
}
Zach Klippenstein (he/him) [MOD]
04/25/2021, 2:56 PMInteractionSource
exposes a Flow
of `Interaction`s, it would probably be simpler to stick to the flow APIs and collect this flow in a LaunchedEffect
instead of converting things to `State`s.Zach Klippenstein (he/him) [MOD]
04/25/2021, 2:58 PMMichal Klimczak
04/25/2021, 3:02 PMcollectIsDraggedAsState
does), but I'm wondering anyway - is this how you change State
change to event
or not really.Zach Klippenstein (he/him) [MOD]
04/25/2021, 3:08 PMLaunchedEffect
launches a new coroutine every time, but you don’t need a coroutine for these non-suspending callbacks). Another way would be to use snapshotFlow
.Zach Klippenstein (he/him) [MOD]
04/25/2021, 3:09 PMLaunchedEffect
also has the disadvantage of requiring recomposition to signal the state change to your callback. Using snapshotFlow
wouldn’t.Zach Klippenstein (he/him) [MOD]
04/25/2021, 3:23 PMLaunchedEffect
like this means your callbacks won’t get invoked until after the composition is applied, which I think means that there will be a frame that gets rendered between when the state actually changes (which invalidates recompose scopes reading it, triggering recomposition) and the frame that will end up rendering any state changes made by your callback, which could result in visual flicker. That’s probably the more important reason to not use this technique.
I’m not sure if the snapshotFlow
method would have this problem, since the flow logic would run as soon as the snapshot that changes the underlying state was committed. I think it still might, because if the underlying state is changed outside a snapshot, the changes would only be seen when the global snapshot is applied which would only happen when compose is preparing the next frame, at which point it would be too late to make state changes that would affect that frame. If the underlying state changes are being performed inside an explicit snapshot though, it might work. I’d need to actually try it to see.
RippleIndication
uses the snapshotFlow approach though so it’s probably fine.Michal Klimczak
04/25/2021, 3:28 PM