0

I have been trying to animate the transition between 2 views that contain Form views in SwiftUI. However the layout breaks only when the animation applies.

This is a fully reproducible example. (Only reproduces on a real device/simulator - not in a playground).

Why does the view break in this way? Is there a workaround to tell the view to re-layout correctly? (iOS 15, XCode 13.2)

struct ContentView: View {
    @State var first = true
    @State var presented = false
    
    var body: some View {
        Button("show") {
            presented.toggle()
        }.fullScreenCover(isPresented: $presented) {
            if first {
                Form {
                    Section(header: Text("First")) {
                        TextField("Name", text: .constant("foobar"))
                    }
                    Section(header: Text("Description")) {
                        TextEditor(text: .constant("foobar"))
                            .frame(minHeight: 200)
                    }
                    Button("next") {
                        withAnimation() {
                            first.toggle()
                        }
                    }
                }
                .transition(.opacity)
            } else {
                Form {
                    Section(header: Text("Second")) {
                        TextField("Name", text: .constant("foobar"))
                    }
                    Section(header: Text("Description")) {
                        TextEditor(text: .constant("foobar"))
                            .frame(minHeight: 200)
                    }
                    Button("previous") {
                        withAnimation() {
                            first.toggle()
                        }
                    }
                }.transition(.opacity)
            }
        }
    }
}

Here is a gif of the problem:

Bug Gif

gh123man
  • 1,372
  • 1
  • 14
  • 24

1 Answers1

0

Check Demystify Swiftui https://developer.apple.com/videos/play/wwdc2021/10022/

Working fine if you keep Form while transition happens

struct ContentView: View {
    @State var first = true
    @State var presented = false

    var body: some View {
        Button("show") {
            presented.toggle()
        }.fullScreenCover(isPresented: $presented) {
            Form {
                if first {
                    Section(header: Text("First")) {
                        TextField("Name", text: .constant("foobar"))
                    }
                    .transition(.opacity)
                    Section(header: Text("Description")) {
                        TextEditor(text: .constant("foobar"))
                            .frame(minHeight: 200)
                    }
                    .transition(.opacity)
                    Button("next") {
                        withAnimation {
                            first.toggle()
                        }
                    }
                    .transition(.opacity)
                } else {
                    Section(header: Text("Second 2")) {
                        TextField("Name 2", text: .constant("foobar 2"))
                    }
                    .transition(.opacity)
                    Section(header: Text("Description 2")) {
                        TextEditor(text: .constant("foobar 2"))
                            .frame(minHeight: 200)
                    }
                    .transition(.opacity)
                    Button("previous") {
                        withAnimation {
                            first.toggle()
                        }
                    }
                    .transition(.opacity)
                }
            }
        }
    }
}
ChanOnly123
  • 1,004
  • 10
  • 12