https://kotlinlang.org logo
#compose
Title
# compose
a

andani

09/20/2020, 7:44 PM
Hi, I'm trying to animate the UI by changing ConstraintSet in ConstraintLayout. But it reflects the UI changes immediately without animating. Am I missing something or is it something not implemented yet? Thanks in advance. You can find the code in the thread.
Copy code
@Composable
fun AnimateUI() {
    val (isExpanded, setIsExpanded) = remember { mutableStateOf(true) }

    val constraints = if (isExpanded) {
        createConstraintSetWith(margin = 16.dp)
    } else {
        createConstraintSetWith(margin = 64.dp)
    }

    ConstraintLayout(constraints) {
        Button(
            onClick = { setIsExpanded(isExpanded.not()) },
            modifier = Modifier.layoutId("button")
        ) {
            Text("Button")
        }

        Text("Text", Modifier.layoutId("text"))
    }
}

private fun createConstraintSetWith(margin: Dp): ConstraintSet {
    return ConstraintSet {
        val button = createRefFor("button")
        val text = createRefFor("text")

        constrain(button) {
            top.linkTo(<http://parent.top|parent.top>, margin = margin)
        }
        constrain(text) {
            top.linkTo(button.bottom, margin)
        }
    }
}
v

Vinay Gaba

09/20/2020, 7:53 PM
You aren’t using any animation composables to actually do the animation. I updated your code. Try this and it should work as intended.
Copy code
@Composable
fun AnimateUI() {
    val (isExpanded, setIsExpanded) = remember { mutableStateOf(true) }
    val margin = animate(if (isExpanded) 16.dp else 64.dp)
    val constraints = createConstraintSetWith(margin = margin)
    ConstraintLayout(constraints) {
        Button(
            onClick = { setIsExpanded(isExpanded.not()) },
            modifier = Modifier.layoutId("button")
        ) {
            Text("Button")
        }
        Text("Text", Modifier.layoutId("text"))
    }
}
You can also pass more properties to the
animate
function to customize you animation behavior (like duration, easing, etc)
The animate function is what allows the values to be smoothly updated. Without it, the value of margin is just toggling between 16.dp and 64.dp. What we instead want is to also have values between 64dp & 64.dp so that the transition feels smooth. Hopefully that makes sense.
h

Halil Ozercan

09/20/2020, 7:57 PM
@Vinay Gaba this sure gets the job done for this example but I think there can be a variant of
animate
function which works for ConstraintSets. There are already many
animate
functions for language primitives as well as compose primitives like
Dp
,
Size
, etc. Maybe the developers can write their own animate functions for ConstraintSets by using these primitive animate values but an obstacle is
constrain
function's scope is not composable.
a

andani

09/20/2020, 7:58 PM
This example is just a simple example that changes margin. When I want to link a view to another view in different states, how
animate
can help me? The animation that I want to implement is

this

. With the ConstraintLayout exists in androidx, I can create different XML files, and clone their ConstraintSet and apply them to the same root. So it will be animated by ConstaintLayout.
v

Vinay Gaba

09/20/2020, 8:00 PM
looks like one way to do this would be a shared element transition which hasn’t been implemented yet.
@Halil Ozercan I have a feeling that I had seen something of that sort somewhere. Couldn’t find it so thought maybe I was imagining things 😄
a

andani

09/20/2020, 8:01 PM
This is the ConstraintSet that I created for the initial state:
Copy code
ConstraintSet {
    val leftGuideline = createGuidelineFromAbsoluteLeft(0.15f)
    val rightGuideline = createGuidelineFromAbsoluteLeft(0.85f)

    val menuButton = createRefFor("menuButton")
    val status = createRefFor("status")
    val cover = createRefFor("cover")

    val movieTitle = createRefFor("movieTitle")
    val description = createRefFor("description")
    val rating = createRefFor("rating")

    constrain(menuButton) {
        start.linkTo(parent.start, 16.dp)
        top.linkTo(<http://parent.top|parent.top>, 16.dp)
    }

    constrain(status) {
        start.linkTo(leftGuideline, 16.dp)
        top.linkTo(menuButton.bottom, 8.dp)
    }

    constrain(cover) {
        start.linkTo(leftGuideline, 16.dp)
        end.linkTo(rightGuideline, 16.dp)
        top.linkTo(status.bottom, 36.dp)

        width = Dimension.fillToConstraints
    }

    createVerticalChain(
        movieTitle, description, rating,
        chainStyle = ChainStyle.Packed
    )

    constrain(movieTitle) {
        start.linkTo(leftGuideline, 16.dp)
        top.linkTo(cover.bottom, 24.dp)
        bottom.linkTo(<http://description.top|description.top>)
    }

    constrain(description) {
        start.linkTo(leftGuideline, 16.dp)
        top.linkTo(movieTitle.bottom)
        bottom.linkTo(<http://rating.top|rating.top>, 16.dp)
    }

    constrain(rating) {
        start.linkTo(leftGuideline, 16.dp)
        bottom.linkTo(parent.bottom, 16.dp)
        top.linkTo(description.bottom)
    }
}
And other states will have different links and margins 😄
v

Vinay Gaba

09/20/2020, 8:44 PM
FWIW, MotionLayout support in compose is currently under development. I think that would also help
a

andani

09/20/2020, 8:44 PM
The reason it doesn't animate is probably that I don't call
TransitionManager.beginDelayedTransition(root)
when change the ConstraintSet because I don't know if there is an equivalent of it in Compose. When I don't call it while using androidx.ConstraintLayout, it performs the same behavior which doesn't animate the UI.
@Vinay Gaba I missed that part. Thanks for letting me know. Looks like, I should wait for it. Until then, maybe I can try some Layout implementations to animate views 🙂
5 Views