1

I am using a List in my app with some rows containing VStacks. I'm using a list and not a LazyVStack inside a ScrollView because I want to leverage some of the List features such as moving rows, swipe, etc.

When I try to add elements to a VStack in a list row with animation I get some jerky behavior and wondering if anyway to avoid this. My example to replicate this behavior is below:

struct ListAnimation: View {
    
    @State var showSecondText = false
    
    var body: some View {
        //ScrollView {
            List {
                VStack(alignment: .center) {
                    Text("First Text Title")
                    if showSecondText {
                        Text("Second Text Title")
                    }
                }
                .frame(maxWidth: .infinity)
                Button {
                    withAnimation {
                        showSecondText.toggle()
                    }
                } label: {
                    Text("Show Second Text")
                }
            }
        //}
    }
}

Uncommenting ScrollView and changing List to LazyVStack will make the animation very smooth. But in the List case, the animation is jerky and the First Text Title jumps up and down during the animation instead of staying in place. With larger more complex data the jerky animations are much more noticeable.

Is there anyway to avoid this when adding elements to a VStack in list row?

alionthego
  • 8,508
  • 9
  • 52
  • 125
  • It looks like a bug where a change in the height of a `List` isn't animated. I suggest that you see if you can reproduce it in ios17 beta and then submit a feedback ticket. It may get fixed. – Paulw11 Jun 07 '23 at 03:51
  • I'll try iOS 17 Beta and see if it persists. If so I'll follow your suggestion and submit a feedback ticket. Thx. – alionthego Jun 07 '23 at 05:39
  • iOS 17 simulator has the same "jump" in height. – Paulw11 Jun 08 '23 at 05:54

2 Answers2

1

Apply the .animation() modifier to VStack and also update the flag with block of Animation. Use below code to achieve your expected output.

   List {
        VStack(alignment: .center) {
            Text("First Text Title")
            if showSecondText {
                Text("Second Text Title")
            }
        }
        .animation(.linear(duration: 0.5)) //Here apple animation modifier to VStack
        .frame(maxWidth: .infinity)

        Button {
            withAnimation(.linear(duration: 0.5)) { //Update the flag with animation also
                showSecondText.toggle()
            }
        } label: {
            Text("Show Second Text")
        }
    }
0

You are not adding to the list, but adding to the VStack, hence the unexplained behaviour. The list sees the VStack as a single row.

You can add multiple items to the List directly.

List {
    Text("First Text Title")
    if showSecondText {
        Text("Second Text Title")
    }
    Button {
        withAnimation {
            showSecondText.toggle()
        }
    } label: {
        Text("Show Second Text")
    }

}

List has an implicit ScrollView (as does Form), so you don’t need to add one.

Chris
  • 4,009
  • 3
  • 21
  • 52
  • 1
    I may have worded the question incorrectly and I'll edit that. I want to add to the VStack in the list and avoid the messy animation. – alionthego Jun 06 '23 at 22:25
  • 1
    Also, I'm not suggesting adding a ScrollView to a List. I'm saying if you change the List to A LazyVStack inside a ScrollView the behavior and animations are normal. – alionthego Jun 06 '23 at 22:28
  • @alionthego Ah I see - sorry. Let me think. – Chris Jun 06 '23 at 22:43
  • I’m not at my computer now to test this, but as it is the `List` row that needs to expand, I wonder if adding an animation modifier to the `List` might work: `.animation(.default, value: showSecondText)` – Chris Jun 06 '23 at 22:53
  • 1
    This might be useful: https://stackoverflow.com/questions/70623529/stop-views-bouncing-in-a-swiftui-list-row-when-adding-child-views?rq=1 – Chris Jun 06 '23 at 23:06
  • 1
    I've tried .animation modifiers and it didn't work. The link you provided is interesting and indeed the same behavior but the solution from Asperi is assuming you know the beginning and end heights. in my case I don't know the heights of each element as items are added and the VStack grows in height. – alionthego Jun 06 '23 at 23:17