1

I'm trying to put together an effect that looks something like iOS's in place table editing. When in "edit mode" selection controls slide in on one side of each row. I did this using a simple AnimatedVisibility on my selection button and tweaking the enter/exit parameters. The button itself looks nice, but the other elements of my row don't also animate their placement. They just snap update at the end? How should I go about getting this "selection button slides in AND the other widgets bunch up a little to make room for" effect as I go in and out of the "edit mode"?

The code I'm currently using for the rows looks like:

Row(
    modifier = Modifier
        .fillMaxWidth()
        .padding(vertical = 10.dp),
    verticalAlignment = Alignment.CenterVertically
) {
    Icon( ... )
    Spacer(modifier = Modifier.width(4.dp))
    Text(text = keyInfo.name, modifier = Modifier.weight(1.0f), maxLines = 1)
    Spacer(modifier = Modifier.width(10.dp))
    SettingsLabel(text = keyInfo.created.shortPrinted())
    AnimatedVisibility(visible = allowSelection,
        enter = slideInHorizontally(initialOffsetX = { w -> w }),
        exit = slideOutHorizontally(targetOffsetX = { w -> w })
    ) {
        IconButton(
            onClick = onSelectionClick, modifier = Modifier
                .padding(start = 16.dp)
                .size(28.dp)
        ) {
            when (isSelected) {
                true -> Icon(
                    Icons.Outlined.CheckCircle, "${keyInfo.name} selected for edit"
                )
                false -> Icon(
                    Icons.Default.RadioButtonUnchecked, "${keyInfo.name} not selected for edit"
                )
            }
        }
    }
}
Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
Travis Griggs
  • 21,522
  • 19
  • 91
  • 167

1 Answers1

5

You can combine Enter/ExitTransitions with the + sign. Combining slideInHorizontally with expandHorizontally, and slideOutHorizontally with shrinkHorizontally will give you the result you want. You may want to tweak the speed and values to match exactly what you need.

AnimatedVisibility(visible = allowSelection,
    enter = slideInHorizontally(initialOffsetX = { w -> w }) + expandHorizontally(expandFrom = Alignment.End),
    exit = slideOutHorizontally(targetOffsetX = { w -> w }) + shrinkHorizontally(shrinkTowards = Alignment.End)
)

enter image description here

eten
  • 803
  • 3
  • 14
  • Oh wow! That makes it look so much better. I'm a little confused why this works? Both pieces cause this thing to show up in the Row composition, but only one seems to cause the Row composition to animatedly adjust the sibling elements. Why is that? I feel like that's key to understanding something I'm missing here. – Travis Griggs Mar 31 '23 at 14:54
  • @TravisGriggs expandHorizontally and shrinkHorizontally [only animate the bounds of the content](https://developer.android.com/reference/kotlin/androidx/compose/animation/package-summary#shrinkHorizontally(androidx.compose.animation.core.FiniteAnimationSpec,androidx.compose.ui.Alignment.Horizontal,kotlin.Boolean,kotlin.Function1)), meanwhile slideIn and slideOut actually transform the content. – eten Mar 31 '23 at 15:13
  • Either way, they both change the layout box of the content. slide changes the origin while leaving the size the same. shrink/expand change size and *may* change the origin depending on what it expands/shrinks towards. – Travis Griggs Apr 01 '23 at 17:18