https://kotlinlang.org logo
Title
a

Alexandru Hadăr

03/30/2022, 10:25 AM
I’ve seen that the first few times I’m using
AnimatedVisibility
, the animation seems a bit staggering/sluggish. After I’ve played a coupled of times with it, it moves smoothly. I tend to believe this is due to some kind of lazy initialization? Or what could be the case and what could be the solution? I’m using compose version
1.1.1
🧵
If you look at the video, first time I open the top-card it staggers a bit, afterwards it move perfectly
I’ve thought that it’s caused by the merging of
expand
+
fade
, but then I changed to
AnimatedVisibility(
            visible = selected,
            enter = expandVertically(
                animationSpec = spring(stiffness = Spring.StiffnessHigh)
            ),
            exit = shrinkVertically(
                animationSpec = spring(stiffness = Spring.StiffnessHigh)
            ))
and it’s the result you see in the video
f

f.babic

03/30/2022, 11:20 AM
could you be doing some data processing/fetching when expanding the item? or showing/hiding new content that has to process some state? It could be that the animation is okay, but the data load and/or render is too much to go alongside an animation
a

Alexandru Hadăr

03/30/2022, 11:31 AM
@f.babic that’s not the case. I’m just displaying some items on the screen
@ExperimentalAnimationApi
@Composable
fun CollapsableCard(article: Article) {
    var selected by remember(article) { mutableStateOf(false) }
    val stiffnes: Float = Spring.StiffnessMedium
    val borderColor = animateColorAsState(targetValue = if (selected) LimedSpruce else LightGray)
    Column(
        modifier = Modifier
            .fillMaxWidth()
            .clip(RoundedCornerShape(8.dp))
            .clickable { selected = !selected }
            .border(BorderStroke(2.dp, borderColor.value), shape = RoundedCornerShape(8.dp))
            .padding(8.dp)
    ) {
        article.image?.let { photoUrl ->
            AnimatedVisibility(
                visible = selected,
                enter = expandVertically(
                    animationSpec = spring(stiffness = stiffnes)
                ),
                exit = shrinkVertically(
                    animationSpec = spring(stiffness = stiffnes)
                )
            ) {
                Box(modifier = Modifier
                    .fillMaxWidth()
                    .height(100.dp)
                    .background(Color.Red))
            }
        }

        Spacer(Modifier.height(12.dp))
        Row(
            verticalAlignment = Alignment.CenterVertically,
            modifier = Modifier.padding(horizontal = 8.dp)
        ) {
            Icon(
                painter = painterResource(id = R.drawable.ic_streak), contentDescription = null,
                Modifier
                    .size(36.dp)
                    .clip(CircleShape)
                    .background(LightGray)
                    .padding(8.dp)
            )
            Spacer(modifier = Modifier.width(8.dp))
            Text(article.title, style = MaterialTheme.typography.subtitle1, fontWeight = FontWeight.Bold)
        }
        Spacer(Modifier.height(12.dp))

        AnimatedVisibility(
            visible = selected,
            enter = expandVertically(
                animationSpec = spring(stiffness = stiffnes)
            ),
            exit = shrinkVertically(
                animationSpec = spring(stiffness = stiffnes)
            )
        ) {
            Column {
                article.description?.let {
                    Text(
                        text = it,
                        style = MaterialTheme.typography.body2,
                        modifier = Modifier.padding(start = 8.dp, end = 8.dp, bottom = 8.dp)
                    )
                }
                Row(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(bottom = 8.dp),
                    horizontalArrangement = Arrangement.SpaceBetween
                ) {
                    ButtonWithIcon(
                        modifier = Modifier.weight(1f),
                        iconRes = R.drawable.ic_headphones_24dp,
                        text = "Listen"
                    )
                    Spacer(modifier = Modifier.width(16.dp))
                    ButtonWithIcon(
                        modifier = Modifier.weight(1f),
                        iconRes = R.drawable.ic_read_24dp,
                        text = "Read"
                    )
                }
            }

        }
    }
}
This is the full code
f

f.babic

03/30/2022, 11:34 AM
Yeah this seems fairly simple 😢 we do have some use cases where the visibility was janky, but because we had to set some state and load images from the web etc, but this is not the case
r

Rick Regan

03/30/2022, 11:58 AM
I wonder if this is due to the delay after initial app startup (see https://kotlinlang.slack.com/archives/CJLTWPH7S/p1630248668315800?thread_ts=1630247931.314700&cid=CJLTWPH7S for example)
a

Alexandru Hadăr

03/30/2022, 12:00 PM
I’ll look into that, @Rick Regan, thanks for the thread.
r

Rick Regan

03/30/2022, 12:00 PM
d

Doris Liu

03/31/2022, 7:36 PM
The jank seems like the result of low frame rate to me. Animation tends to surface performance issues, as it requires changes every frame. Is this reproducible on a release build?
a

Alexandru Hadăr

04/15/2022, 12:30 PM
Hey @Doris Liu, sorry for not replying to you. I will create a release build from it and come back to you.