SwiftUIのAlertが使いにくかったので、Extensionを作りました。
2021/3/16追記
View以外のコードからアラートを呼び出す方法もありました。コードから呼び出す方が汎用的だと思います。
[SwiftUI] コード(ViewModelなど)からAlertを表示する方法
実装
AlertData.swift
struct AlertData {
let title: String
let message: String?
let primaryText: String?
let primaryAction: (() -> ())?
let secondaryText: String?
let secondaryAction: (() -> ())?
init(title: String, message: String? = nil, primaryText: String? = nil, primaryAction: (() -> ())? = nil, secondaryText: String? = nil, secondaryAction: (() -> ())? = nil) {
self.title = title
self.message = message
self.primaryText = primaryText
self.primaryAction = primaryAction
self.secondaryText = secondaryText
self.secondaryAction = secondaryAction
}
}
View+.swift
import SwiftUI
extension View {
/// Alertを表示する
///
/// 使い方
///
/// Button("Show Alert") {
/// showingAlert = true
/// }
/// .alert(isPresented: $showingAlert,
/// data: AlertData(title: "title",
/// message: "message",
/// primaryText: "primary",
/// primaryAction: {
/// print("primary tapped")
/// },
/// secondaryText: "secondary",
/// secondaryAction: {
/// print("secondary tapped")
/// }))
func alert(isPresented: Binding<Bool>, data: AlertData) -> some View {
let title = Text(data.title)
var messageText: Text? = nil
if let message = data.message {
messageText = Text(message)
}
var primaryButton: Alert.Button? = nil
if let primaryText = data.primaryText {
primaryButton = .default(Text(primaryText)) {
_ = data.primaryAction?()
}
}
var secondaryButton: Alert.Button? = nil
if let secondaryText = data.secondaryText {
secondaryButton = .default(Text(secondaryText)) {
_ = data.secondaryAction?()
}
}
if let primaryButton = primaryButton, let secondaryButton = secondaryButton {
return AnyView(alert(isPresented: isPresented, title: title, message: messageText, primaryButton: primaryButton, secondaryButton: secondaryButton))
} else if let primaryButton = primaryButton {
return AnyView(alert(isPresented: isPresented, title: title, message: messageText, dismissButton: primaryButton))
} else if let secondaryButton = secondaryButton {
return AnyView(alert(isPresented: isPresented, title: title, message: messageText, dismissButton: secondaryButton))
} else {
return AnyView(alert(isPresented: isPresented, title: title, message: messageText))
}
}
private func alert(isPresented: Binding<Bool>, title: Text, message: Text?) -> some View {
alert(isPresented: isPresented) {
Alert(title: title, message: message)
}
}
private func alert(isPresented: Binding<Bool>, title: Text, message: Text?, primaryButton: Alert.Button, secondaryButton: Alert.Button) -> some View {
alert(isPresented: isPresented) {
Alert(title: title, message: message, primaryButton: primaryButton, secondaryButton: secondaryButton)
}
}
private func alert(isPresented: Binding<Bool>, title: Text, message: Text?, dismissButton: Alert.Button) -> some View {
alert(isPresented: isPresented) {
Alert(title: title, message: message, dismissButton: dismissButton)
}
}
}