I'd like to do a `Crossfade` on a `Text` when it is set to the empty string, but not when it is upda...
r
I'd like to do a
Crossfade
on a
Text
when it is set to the empty string, but not when it is updated in any other way. This code will crossfade for every update to the state 'text'
Copy code
Crossfade(targetState = text, animationSpec = tween(1000)) { newText ->
    Text(text = newText)
}
but I'd only like it to apply when 'text' is cleared. Is it possible to do this with Crossfade, or do I need some other animation mechanism? (I didn't expect using
if (text.isEmpty())
with a crossfaded Text in the
if
and just a Text in the
else
to work, but I tried it anyway and it didn't.)
a
AnimatedVisibility
might be more appropriate for this use case
r
Thanks I will look into it
I don't think
AnimatedVisibility()
is going to do it because with parameter
visible = text.isNotEmpty()
, the animation kicks in when the text is empty, which I is what I want, but then there's nothing to animate (empty string). Even if I could get
AnimatedVisibility()
to work for Text, I don't know what I would use for Slider, which is the other widget I would like to fade to a new setting (but only upon "resetting" it through a button, not during interaction with the thumb).
d
For the text, you could remember the non-empty text in the
AnimatedVisibility
content body
Copy code
AnimatedVisibility(visible = text.isNotEmpty()) {
   var textToDisplay by remember { mutableStateOf(text) }
   if (text.isNotEmpty) { textToDisplay = text }
   Text(text)
}
Hmm... this may be a useful pattern.
Can you show a demo of the effect of the Slider that you are trying to achieve?
r
I was trying to think of a good way to work in using the previous value but then I thought that was getting messy -- but you're solution of a local
remember
(coded as below) looks pretty good.
Copy code
AnimatedVisibility(
    visible = text.isNotEmpty(),
    enter = fadeIn(animationSpec = tween(1000)),
    exit = fadeOut(animationSpec = tween(1000))
) {
    var textToDisplay by remember { mutableStateOf(text) }
    if (text.isNotEmpty()) { textToDisplay = text }
    Text(textToDisplay)
}
Here's a little code sample to show the Slider crossfade effect I'm after (I don't want it to crossfade for every move, as coded, but just for "reset").
Copy code
@Composable
fun AnimateSlider(
) {
    var sliderPosition by remember { mutableStateOf(0f) }
    Column {
        Crossfade(targetState = sliderPosition, animationSpec = tween(2000)) { newSliderPosition ->
            Slider(
                value = newSliderPosition,
                onValueChange = { sliderPosition = it },
                valueRange = 0f..100f,
                steps = 5
            )
        }
        Button(
            onClick = {sliderPosition = 0f }
        ) {
            Text(text = "Reset")
        }

    }
}
I don't know if I could do this with the current low-level animation APIs, but I will look into it.
d
For something simple as a string, this could be useful, and it's nice this
textToDisplay
has the same lifecycle as
Text
below - i.e. disposed after animating out.
For the slider, you could create an object that holds Slider
value
and
onValueChnage
, and use that object as the targetState for
Crossfade
. When reset button is clicked, create a new object.
You may also want to watch out for touch being registered on the wrong slider during the animation.
r
Actually, as cool as the
AnimatedVisibility
pattern is, I realize now that I've plugged it into my app (instead of my Compose test project) it doesn't give me what I'm looking for. It will remove the whole
Text
(of course), including the borders (I have a Text of specified size with a border that I want to stick around when the text is cleared). Crossfade on the text value at least just affects that, and leaves everything else (e.g., modifier) alone. (But I'll put this trick in the bank for some possible future use.)
👍 1
Wow, very cool trick with the
targetState
object for Slider. It doesn't crossfade for normal operation because the changing slider position is hidden inside the object. As far as registering on the wrong slider, I don't see the issue: if I touch it during animation, it just gets recorded in that new object, right? It effectively overrides the reset, which should be OK. Aside from seeing the right side thumb fading while the new one appears (I tested with a long
tween
time), it appears to work.
I just realized -- that same trick will work for Text too! If I put the text in an object, and create a new object with an empty string when I hit the clear button, it will work the same way. Thanks so much for your help.
👍 1