swiftuiswiftui-listswiftui-animationsf-symbols

SwiftUI symbol effects animate on scrolling list only when in Stack view


When: Embedding a Image with a symbol effect in a stack view in SwiftUI, and putting this in a List

Actual: The symbols animate when scrolling that item in and out of the view

Expected: The symbol doesn't animate until the value changes.

I have the following code which is boiled down from my actual code where the animating value is a @Model object property (other animations work fine when their animation's value is watching the same property.

I've boiled it down to the below examples:

The top example works as expected (no symbol animations on scroll) The bottom example animates the symbols every time they scroll in to view

#Preview {
    VStack {
        List {
            ForEach(1...100, id: \.self) { index in
                Image(systemName: "square.3.layers.3d")
                    .symbolEffect(.bounce, value: index)
            }
        }
        
        List {
            ForEach(1...100, id: \.self) { index in
                HStack {
                    Image(systemName: "square.3.layers.3d")
                        .symbolEffect(.bounce, value: index)
                }
            }
        }
    }
}

This happens on Mac and iOS.

I'm running Xcode 15.3 RC2 but it also happens in Xcode 15.2

I've found the below example will happen whether it's a HStack, VStack or ZStack but seems fine in a Group.

I've tried adding a id() modifier to the HStack to give it an explicit identifier but this doesn't seem to work.

Is there something I'm missing here?


Solution

  • The only substantial difference I can see between the two Lists is that the Images in the top list are assigned an id by the ForEach, but in the bottom list, the ForEach assigns its ids to the HStack instead.

    Assigning an id manually to the images creates the same behaviour as the top list.

    List {
        ForEach(1...100, id: \.self) { index in
            HStack {
                Image(systemName: "square.3.layers.3d")
                    .symbolEffect(.bounce, value: index)
                    .id(index)
            }
        }
    }