Search code examples
swiftswiftui

How to prevent parent view animations from overriding that of a child view?


When the user presses the button to show the rectangle, the offset animation that of the text should not be overridden by the .smooth(duration: 0.25) but instead continue its 50 second linear animation.

Below is the full example.

struct ContentView: View {
    @State private var showingRect = false
    var body: some View {
        VStack {
            Button("Show Rect") {
                withAnimation(.smooth(duration: 0.25)) {
                    showingRect.toggle()
                }
            }
            
            TextView()
            
            if showingRect {
                Rectangle()
                    .foregroundStyle(.blue)
                    .frame(width: 100, height: 100)
            }
            
        }
        .padding()
    }
}

struct TextView: View {
    @State private var animate = false
    
    var body: some View {
        Text("This is a very long text. Yeah, it is very very long.")
            .lineLimit(1)
            .offset(x: animate ? -300 : 0)
            .onAppear {
                withAnimation(.linear(duration: 50)) {
                    animate = true
                }
            }
    }
}

Solution

  • Use .animation(nil, value: showingRect) on the TextView to say that when showingRect changes, TextView should not be animated.

    TextView()
        .animation(nil, value: showingRect)
    

    If you still want the text to be animated upwards to fit the new rectangle, add .geometryGroup:

    TextView()
        .geometryGroup()