SwiftUI:pushViewController:animated:在现有过渡或演示发生时调用...

SwiftUI: pushViewController:animated: called on ... while an existing transition or presentation is occurring

我想从警报中导航到详细信息视图。

这里是错误的最小可重现代码示例:

struct ContentView: View {

    let items = ["1", "2", "3", "4"]

    var body: some View {
        NavigationView {
            List {
                ForEach(items, id: \.self) { item in
                    RowView(item: item)
                }
            }
        }
    }
}

struct RowView: View {

    let item: String

    @State private var isShowingNext = false
    @State private var isShowingAlert = false

    var body: some View {

        let itemNumber = Int(item)!
        let isEven = itemNumber % 2 == 0

        ZStack {
            if isEven {
                NavigationLink(
                    destination: Text("Hello"),
                    isActive: $isShowingNext,
                    label: {
                        Text(item)
                    }
                ).hidden()
                Button(
                    action: {
                        isShowingAlert.toggle()
                    }, label: {
                        Text("\(item) (with alert)")
                    }
                )
                .alert(isPresented: $isShowingAlert) {
                    Alert(
                        title: Text("Alert")
                            .foregroundColor(Color.red)
                            .font(.title),
                        message: Text("Hello"),
                        primaryButton: .destructive(
                            Text("Navigate"),
                            action: {
                                isShowingNext = true
                            }
                        ),
                        secondaryButton: .cancel()
                    )
                }
            } else {
                NavigationLink(
                    destination: Text("Hello"),
                    isActive: $isShowingNext,
                    label: {
                        Text(item)
                    }
                )
            }
        }
    }
}

当您点击例如项目 2 (with alert) 警报出现,但错误也出现在控制台中。然后,当您在警报中单击 Navigate 时,它不会导航。

可能是什么问题?

AlertNavigationLink都呈现了另一种观点。当另一个视图已经显示在当前视图上时,您不能显示一个视图。

您必须等到 Alert 被隐藏,然后您才能显示 NavigationLink

最简单的方法是将 Binding 传递给 NavigationLink,这将确保 Alert 不显示:

struct RowView: View {

    let item: String

    @State private var isShowingNext = false
    @State private var isShowingAlert = false

    private var isShowingNextBinding: Binding<Bool> {
        Binding(
            get: {
                !isShowingAlert && isShowingNext
            }, set: {
                isShowingNext = [=10=]
            }
        )
    }

    var body: some View {

        let itemNumber = Int(item)!
        let isEven = itemNumber % 2 == 0

        ZStack {
            if isEven {
                NavigationLink(
                    destination: Text("Hello"),
                    isActive: isShowingNextBinding,
                    label: {
                        Text(item)
                    }
                ).hidden()
                Button(
                    action: {
                        isShowingAlert.toggle()
                    }, label: {
                    Text("\(item) (with alert)")
                }
                )
                    .alert(isPresented: $isShowingAlert) {
                        Alert(
                            title: Text("Alert")
                                .foregroundColor(Color.red)
                                .font(.title),
                            message: Text("Hello"),
                            primaryButton: .destructive(
                                Text("Navigate"),
                                action: {
                                    isShowingNext = true
                                }
                            ),
                            secondaryButton: .cancel()
                        )
                    }
            } else {
                NavigationLink(
                    destination: Text("Hello"),
                    isActive: $isShowingNext,
                    label: {
                        Text(item)
                    }
                )
            }
        }
    }
}