Search code examples
animationswiftuiios-animations

Animating row change in a List with SwiftUI


Focusing on comprehending the underlying concept of the various animation behaviors, I am interested of programmatically animate the change of a row in a List.

I am able to achieve it in the following example:

struct First: View {
  @State var items = ["One", "Two", "Three", "Four"]

  var body: some View {
    VStack {
        List(items, id: \.self) { item in
            Text(item)
        }
        
        Button("Hit me") {
            withAnimation {
                items.swapAt(2, 0)
            }
        }
    }
 }
}

As you can see upon tapping on the button, we receive a nice swapping animation in the cells. We can see that cells are actually moving, one to the top and the other downwards:

List: nice swapping animation in the cells

When I change the list code to the following:

List(items.indices, id: \.self) { index in
   Text(items[index])
}

As you can see the prior animation doesn't work anymore and instead I receive a text change animation:

List: animation doesn't work anymore and instead I receive a text change animation

Is there a solution to keep the first (default) swapping animation ?

Thanks.


Solution

  • It's a question of identity. SwiftUI keeps track of view elements by their identity, and it can only animate between states when the identities of the single elements stay the same.

    In the first code, the List id is of type String, the string changes place but keeps the same id.

    In the second code the List id is of type Index, but when swapping the index does not change, only the relative string at that index.

    So in result 1. animates the position based on string id, and 2. animates the string based on index id.

    BUT you can tell SwiftUI explicitly which id to use, also in the second code, like this:

                List(items.indices, id: \.self) { index in
                    Text(items[index]).id(items[index]) // Here
                }