Rick Regan

    Rick Regan

    1 year ago
    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'
    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.)
    Adam Powell

    Adam Powell

    1 year ago
    AnimatedVisibility
    might be more appropriate for this use case
    Rick Regan

    Rick Regan

    1 year ago
    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).
    Doris Liu

    Doris Liu

    1 year ago
    For the text, you could remember the non-empty text in the
    AnimatedVisibility
    content body
    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?
    Rick Regan

    Rick Regan

    1 year ago
    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.
    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").
    @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.
    Doris Liu

    Doris Liu

    1 year ago
    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.
    Rick Regan

    Rick Regan

    1 year ago
    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.)
    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.