SwiftUI 2.0 / Xcode 12中有关父视图和子视图的警报

时间:2020-10-10 01:30:17

标签: swiftui alert

有人可以向我解释为什么这在SwiftUI 2.0 / iOS 14 / Xcode 12和有效的解决方法中不起作用吗? AlertOne可以正常工作,但AlertTwo不能。我正在尝试对父级和子级(嵌套)视图都发出警报。您可以将此权限插入Xcode进行测试(如果需要)。谢谢。

import SwiftUI

struct ContentView: View {
    @State private var alertOne = false

    var body: some View {
        VStack {
            Button("Alert One") {
                self.alertOne.toggle()
            }
            TestView().padding()
        }
        .alert(isPresented: $alertOne) {
            Alert(title: Text("Alert One"), dismissButton: .default(Text("Got it!")))
        }
    }
}

struct TestView: View {
    @State private var alertTwo = false
    
    var body: some View {
        Button("Alert Two") {
            self.alertTwo.toggle()
        }
        .alert(isPresented: $alertTwo) {
            Alert(title: Text("Alert Two"), dismissButton: .default(Text("Got it!")))
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

2 个答案:

答案 0 :(得分:0)

这是一种构造代码的可能方法:

struct ContentView: View {
    @State private var showAlert = false
    @State private var alert: Alert? = nil

    var body: some View {
        VStack {
            Button("Alert One") {
                alert = Alert(title: Text("Alert One"), dismissButton: .default(Text("Got it!")))
                self.showAlert.toggle()
            }
            TestView(showAlert: $showAlert, alert: $alert).padding()
        }
        .alert(isPresented: $showAlert) {
            alert!
        }
    }
}

struct TestView: View {
    @Binding var showAlert: Bool
    @Binding var alert: Alert?
    
    var body: some View {
        Button("Alert Two") {
            alert = Alert(title: Text("Alert Two"), dismissButton: .default(Text("Got it!")))
            self.showAlert.toggle()
        }
    }
}

这里是使用新类型IdentifiableAlert的替代方法。这样一来,您就可以摆脱单独的showAlert并仅在将IdentfiableAlert分配给alert时显示警报:

struct IdentifiableAlert: Identifiable {
    let alert: Alert
    let id = UUID()
}

struct ContentView: View {
    @State private var alert: IdentifiableAlert? = nil

    var body: some View {
        VStack {
            Button("Alert One") {
                alert = IdentifiableAlert(alert: Alert(title: Text("Alert One"), dismissButton: .default(Text("Got it!"))))
            }
            TestView(alert: $alert).padding()
        }
        .alert(item: $alert) { alert in
            alert.alert
        }
    }
}

struct TestView: View {
    @Binding var alert: IdentifiableAlert?
    
    var body: some View {
        Button("Alert Two") {
            alert = IdentifiableAlert(alert: Alert(title: Text("Alert Two"), dismissButton: .default(Text("Got it!"))))
        }
    }
}

这里有一个方便的扩展程序,可以将Alert变成IdentifiableAlert()

extension Alert {
    func identifiable() -> IdentifiableAlert { IdentifiableAlert(alert: self) }
}

所以这个:

alert = IdentifiableAlert(alert: Alert(title: Text("Alert Two"), dismissButton: .default(Text("Got it!"))))

可以替换为:

alert = Alert(title: Text("Alert Two"), dismissButton: .default(Text("Got it!"))).identifiable()

答案 1 :(得分:0)

我认为这是一个错误,但实际上SwiftUI的行为方式是这样的-它不允许在一个视图层次结构中使用多个表或警报(因为我假设它们在内部使用视图首选项,因此一旦设置为一个周期,就不会这样做)更新)。

可能的解决方案是使用一个.alert用于视图层次结构并从不同部分进行配置,或者使用助手宿主视图人为地分隔视图层次结构。

通过Xcode 12 / iOS 14测试

代码中唯一的更改 // ...

    // you can wrap any part at any level to make it independent 
    // on existing view hierarchy !!
    HelperView { TestView().padding() }.fixedSize()

    // ... 

和助手视图

struct HelperView<Content: View>: UIViewRepresentable {
    let content: () -> Content

    func makeUIView(context: Context) -> UIView {
        let controller = UIHostingController(rootView: content())
        return controller.view
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {}
}