Animating SwiftUI Form results in inconsistent UI state

Update: I interpreted the existence of a swiftui tag as it being on-topic (despite suspecting otherwise). Let me know if it's not, but if so then please also contribute to designing around the problem. Admittedly, it's clever to let the author indirectly tag their own post as off-topic this way, but it would be even better if the criteria were explicit.


When running the below example code in the canvas (Xcode 12.4) or on a device (iOS 14.5) I always end up in an inconsistent UI state if I quickly double click the Edit/Cancel button.

It should just insert or remove a Section in the Form , but whenever I activate animations it seems to insert the first section "too late":

Inconsistent Consistent

The first image is after a double click and does not reflect the view's state. More specifically the first section is out of sync with the rest of the UI; the first section should not exist. The second image is after a single click and looks as it should.

I get the same result when using withAnimation in the Button s' action instead of .animation on the Form .

import SwiftUI

struct TestView: View {

    enum Mode: String { case view, edit }

    @State private var mode: Mode = .view

    var modeString: String { "We're in \(mode.rawValue) mode" }
    var modeColor: Color { mode == .view ? .green : .red }
    var title: String { mode.rawValue + " mode" }

    var body: some View {

        let editButton = Button("Edit") { mode = .edit }
        let cancelButton = Button("Cancel") { mode = .view }

        NavigationView {
            Form {
                if mode == .edit {
                    Section(header: Text(modeString)) {
                        Text(modeString).foregroundColor(modeColor)
                    }
                }

                Section(header: Text(modeString)) {
                    Text(modeString).foregroundColor(modeColor)
                }
            }
            .navigationBarItems(trailing: mode == .view ? editButton : cancelButton)
            .navigationBarTitle(title)
            .animation(.default)
        }
    }
}

struct TestView_Previews: PreviewProvider {
    static var previews: some View {
            TestView()
    }
}

Did I misunderstand something?

Terms of Service

Privacy Policy

Cookie Policy