如何在SwiftUI的一个视图上显示两个警报?

Luk*_*ers 4 swift swiftui

我想将两个唯一的警报附加到同一Button视图。当我使用下面的代码时,只有底部的警报起作用。

我正在macOS Catalina上使用Xcode 11的正式版本。

@State private var showFirstAlert = false
@State private var showSecondAlert = false

Button(action: {
    if Bool.random() {
        showFirstAlert = true
    } else {
        showSecondAlert = true
    }
}) {
    Text("Show random alert")
}
.alert(isPresented: $showFirstAlert) {
    // This alert never shows
    Alert(title: Text("First Alert"), message: Text("This is the first alert"))
}
.alert(isPresented: $showSecondAlert) {
    // This alert does show
    Alert(title: Text("Second Alert"), message: Text("This is the second alert"))
}
Run Code Online (Sandbox Code Playgroud)

我希望在设置showFirstAlert为true 时显示第一个警报,而在我设置为true时希望显示第二个警报showSecondAlert。只有第二个警报显示其状态为true时,但第一个警报什么也不做。

Ben*_*Ben 22

这个解决方案有一个变体,它只使用一个状态变量而不是两个。它使用了这样一个事实,即有另一种.alert()形式接受一个Identifiable项目而不是一个 Bool,因此可以传递额外的信息:

struct AlertIdentifier: Identifiable {
    enum Choice {
        case first, second
    }

    var id: Choice
}

struct ContentView: View {
    @State private var alertIdentifier: AlertIdentifier?

    var body: some View {
        HStack {
            Button("Show First Alert") {
                self.alertIdentifier = AlertIdentifier(id: .first)
            }
            Button("Show Second Alert") {
                self.alertIdentifier = AlertIdentifier(id: .second)
            }
        }
        .alert(item: $alertIdentifier) { alert in
            switch alert.id {
            case .first:
                return Alert(title: Text("First Alert"),
                             message: Text("This is the first alert"))
            case .second:
                return Alert(title: Text("Second Alert"),
                             message: Text("This is the second alert"))
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 7

如果您有更复杂的逻辑(例如,来自一个按钮的多个警报),这是另一种灵活的方法。您基本上可以附加.alert到任何View按钮并将警报逻辑与按钮分开,如下所示:

EmptyView() 对我不起作用。在 Xcode 12.4 中测试

// loading alert
Text("")
    .alert(isPresented: $showLoadingAlert, content: {
        Alert(title: Text("Logging in"))
    })
    .hidden()

// error alert
Text("")
    .alert(isPresented: $showErrorAlert, content: {
        Alert(title: Text("Wrong passcode"), message: Text("Enter again"), dismissButton: .default(Text("Confirm")))
    })
    .hidden()
Run Code Online (Sandbox Code Playgroud)

  • 添加框架(宽度:0,高度:0)以看不到视图。如果我隐藏视图,代码将不起作用。 (2认同)

Joh*_* M. 5

的第二个调用将.alert(isPresented)覆盖第一个。您真正想要的是Binding<Bool>指示是否显示警报,以及应该从其后的闭包中返回警报的某些设置.alert(isPresented)。您可以为此使用Bool,但是我继续使用枚举来完成此操作,因为它扩展为两个以上的警报。

enum ActiveAlert {
    case first, second
}

struct ToggleView: View {
    @State private var showAlert = false
    @State private var activeAlert: ActiveAlert = .first

    var body: some View {

        Button(action: {
            if Bool.random() {
                self.activeAlert = .first
            } else {
                self.activeAlert = .second
            }
            self.showAlert = true
        }) {
            Text("Show random alert")
        }
        .alert(isPresented: $showAlert) {
            switch activeAlert {
            case .first:
                return Alert(title: Text("First Alert"), message: Text("This is the first alert"))
            case .second:
                return Alert(title: Text("Second Alert"), message: Text("This is the second alert"))
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

我改进了一点 Ben 的回答。您可以使用 .alert( item: ) 代替 .alert( isPresented: )来动态显示多个警报:

struct AlertItem: Identifiable {
    var id = UUID()
    var title: Text
    var message: Text?
    var dismissButton: Alert.Button?
}

struct ContentView: View {

    @State private var alertItem: AlertItem?

    var body: some View {
        VStack {
            Button("First Alert") {
                self.alertItem = AlertItem(title: Text("First Alert"), message: Text("Message"))
            }
            Button("Second Alert") {
                self.alertItem = AlertItem(title: Text("Second Alert"), message: nil, dismissButton: .cancel(Text("Some Cancel")))
            }
            Button("Third Alert") {
                self.alertItem = AlertItem(title: Text("Third Alert"))
            }
        }
        .alert(item: $alertItem) { alertItem in
            Alert(title: alertItem.title, message: alertItem.message, dismissButton: alertItem.dismissButton)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


mar*_*nax 5

请注意,在 iOS 16 中,一个视图上有两个警报不再是问题。 alert(isPresented:content:)alert(item:content:)在该线程的许多答案中提到的以及该Alert结构均已弃用。

建议仅使用alert(_:isPresented:actions:message:)替代方案或其变体之一。例如:

struct ContentView: View {
    @State private var isFirstAlertPresented = false
    @State private var isSecondAlertPresented = false

    var body: some View {
        VStack {
            Button("Show first alert") {
                isFirstAlertPresented = true
            }
            Button("Show second alert") {
                isSecondAlertPresented = true
            }
        }
        .alert(
            "First alert",
            isPresented: $isFirstAlertPresented,
            actions: {
                Button("First OK") {}
            },
            message: {
                Text("First message")
            }
        )
        .alert(
            "Second alert",
            isPresented: $isSecondAlertPresented,
            actions: {
                Button("Second OK") {}
            },
            message: {
                Text("Second message")
            }
        )
    }
}
Run Code Online (Sandbox Code Playgroud)