SwiftUIで複数のアラートを表示する、連続で表示する
SwiftUIでアラートを表示する
SwiftUIでアラートを表示する基本的な方法
struct ContentView: View {
// アラート表示フラグ
@State var showingAlert = false
var body: some View {
Button {
showingAlert.toggle()
} label: {
Text("アラート")
}
// alert modifierにフラグの参照を渡す
.alert(isPresented: $showingAlert) {
Alert(title: Text("タイトル"),
message: Text("メッセージ"),
primaryButton: .default(Text("OK"), action: {
// OKボタン押下時の処理
}),
secondaryButton: .cancel(Text("キャンセル")))
}
}
}
複数のアラートを出し分け
1つのボタンを押したときに、条件によって異なるアラートを表示したい場合、以下のようにalert modifierを2つ重ねると、宣言の上書きでアラート2しか表示できない。
struct ContentView: View {
@State var showingAlert1 = false
@State var showingAlert2 = false
var body: some View {
Button {
// 条件によってアラート1,2を出し分け
if 条件 {
showingAlert1.toggle() // 表示されない
} else {
showingAlert2.toggle() // 表示される
}
} label: {
Text("アラート")
}
// アラート1
.alert(isPresented: $showingAlert1) {
Alert(title: Text("アラート1"),
message: Text("メッセージ1"),
dismissButton: .default(Text("OK")))
}
// アラート2
.alert(isPresented: $showingAlert2) {
Alert(title: Text("アラート2"),
message: Text("メッセージ2"),
dismissButton: .default(Text("OK")))
}
}
}
これを解決するには以下の方法がある。
① アラートタイプを定義する
② 動的にアラートを生成する
① アラートタイプを定義する
enumのAlertTypeを定義して、1つのalert modifierの中でalertTypeによってAlertを生成して返却する。条件によってalertTypeを設定してから表示フラグをONにすれば、意図したアラートを表示することができる。
// アラートタイプを定義
enum AlertType {
case alert1
case alert2
}
struct ContentView: View {
@State var showingAlert = false
@State var alertType: AlertType = .alert1
var body: some View {
Button {
// 条件によってアラートタイプを設定
if 条件 {
alertType = .alert1
} else {
alertType = .alert2
}
showingAlert.toggle()
} label: {
Text("アラート")
}
.alert(isPresented: $showingAlert) {
// アラートタイプによってAlertを返却
switch alertType {
case .alert1:
return Alert(title: Text("アラート1"),
message: Text("メッセージ1"),
dismissButton: .default(Text("OK")))
case .alert2:
return Alert(title: Text("アラート2"),
message: Text("メッセージ2"),
dismissButton: .default(Text("OK")))
}
}
}
}
② 動的にアラートを生成する
alert(item:content:)というメソッドを使う。Identifiableプロトコルに準拠したAlertItemを定義し、alertItemの内容によってAlertを生成する。条件によってalertItemを変更すれば、意図したアラートを表示できる。
// Identifiableプロトコルに準拠したAlertItemを定義
struct AlertItem: Identifiable {
var id = "id"
var title: Text
var message: Text?
var dismissButton: Alert.Button?
}
struct ContentView: View {
@State var alertItem: AlertItem?
var body: some View {
Button {
// 条件によってアラートアイテムを生成
if 条件 {
alertItem = AlertItem(title: Text("アラート1"), message: Text("メッセージ1"), dismissButton: .default(Text("OK")))
} else {
alertItem = AlertItem(title: Text("アラート2"), message: Text("メッセージ2"), dismissButton: .default(Text("OK")))
}
} label: {
Text("アラート")
}
// アラートアイテムの参照を渡す ※nilの場合はmodifier closureは実行されない
.alert(item: $alertItem) { item in
Alert(title: item.title, message: item.message, dismissButton: item.dismissButton)
}
}
}
アラートの連続表示
条件分岐による出し分けではなく、連続でアラートを表示させたい場合、以下の処理をaction closure内で非同期実行すればよい。
① アラートタイプを定義する場合:alertTypeの更新 & 表示フラグON
② 動的にアラートを生成する場合:alertItemの再生成
// アラートタイプを定義する場合
.alert(isPresented: $showingAlert) {
switch alertType {
case .alert1:
return Alert(title: Text("アラート1"),
message: Text("メッセージ1"),
dismissButton: .default(Text("OK"), action: {
// 非同期実行が必要
DispatchQueue.main.async {
alertType = .alert2
showingAlert.toggle()
}
}))
case .alert2:
return Alert(title: Text("アラート2"),
message: Text("メッセージ2"),
dismissButton: .default(Text("OK")))
}
}
// 動的にアラートを生成する場合
alertItem = AlertItem(title: Text("アラート1"), message: Text("メッセージ1"), dismissButton: .default(Text("OK"), action: {
// 非同期実行が必要
DispatchQueue.main.async {
// alertItemを更新すればアラートを再表示してくれる
alertItem = AlertItem(title: Text("アラート2"), message: Text("メッセージ2"), dismissButton: .default(Text("OK")))
}
}))
参考
この記事が気に入ったらサポートをしてみませんか?