⚒️
SwiftUIで複数のアラートを一つのViewで管理する
はじめに
SwiftUIで複数のタイプのアラートを実装する場面はよくありますが、このようにアラートを実装するとうまく動作しません。
struct ContentView: View {
@State private var showInfoAlert = false
@State private var showWarningAlert = false
var body: some View {
VStack {
Button("情報アラート") {
showInfoAlert = true
}
Button("警告アラート") {
showWarningAlert = true
}
}
.alert("情報", isPresented: $showInfoAlert) {
Button("OK", role: .cancel) { }
} message: {
Text("これは情報アラートです。")
}
.alert("警告", isPresented: $showWarningAlert) {
Button("了解", role: .cancel) { }
} message: {
Text("これは警告アラートです。")
}
}
}
複数の.alert修飾子を同じビューに適用すると、SwiftUIのビュー階層の仕組みによって最後に定義されたアラートしか動作しなくなってしまいます。この例では「警告」アラートのみが機能し、「情報」アラートはボタンを押しても表示されず、無視されてしまいます。
解決策
単一".alert"と表示用のフラグを使用してアラートの表示状態を管理しつつ、enumを使用して異なるアラートを出し分ける方法がわかりやすい解決策の1つです。
import SwiftUI
struct ContentView: View {
@State private var showAlert = false
@State private var alertType: AlertType = .informational
enum AlertType {
case informational
case warning
case confirmation
case error
}
var body: some View {
VStack {
Button("情報アラート") {
alertType = .informational
showAlert = true
}
Button("警告アラート") {
alertType = .warning
showAlert = true
}
Button("確認アラート") {
alertType = .confirmation
showAlert = true
}
Button("エラーアラート") {
alertType = .error
showAlert = true
}
}
.alert(isPresented: $showAlert) {
switch alertType {
case .informational:
return Alert(
title: Text("情報"),
message: Text("これは情報アラートです。"),
dismissButton: .default(Text("OK"))
)
case .warning:
return Alert(
title: Text("警告"),
message: Text("これは警告アラートです。"),
dismissButton: .default(Text("了解"))
)
case .confirmation:
return Alert(
title: Text("確認"),
message: Text("この操作を実行してもよろしいですか?"),
primaryButton: .destructive(Text("実行"), action: {
// 処理をここに記述
}),
secondaryButton: .cancel(Text("キャンセル"))
)
case .error:
return Alert(
title: Text("エラー"),
message: Text("エラーが発生しました。"),
dismissButton: .default(Text("閉じる"))
)
}
}
}
}
このコードでは、一つの".alert"文の中でswitch文を利用して異なるアラートを出し分けています。これによって複数のアラートがしっかり動作する状態にでき、新しいアラートタイプを追加する時もenumに新しいケースを追加するだけでできて簡潔に実装できますね。
Discussion