SwiftUIでalertをスマートに実装する方法を模索中です。
例えば alert(_:isPresented:presenting:actions:message:)
の場合、presenting
に与えるデータの有無に連動して、isPresented
のtrue/falseが切り替わる仕組みがあると、便利と思いました。
Binding
には get/setのクロージャで値変換が可能なイニシャライザがあるので、これを利用してみます。
で、汎用的に使えるように拡張メソッドを作ってみました。
extension Binding {
func bool<T>() -> Binding<Bool> where Value == Optional<T> {
Binding<Bool> (
get: {
self.wrappedValue != nil
},
set: { newValue in
// alertはボタンタップで非表示に変化の時にfalseをsetする。
// その際には、元のOptional値をnilに更新する。
if !newValue {
self.wrappedValue = nil
}
// trueがsetの時は何もしない。
}
)
}
}
alertで利用する場合は、以下のような感じ。
enum AlertKind {
case hello
case world
}
struct DemoView: View {
@State
var alertKind: AlertKind?
var body: some View {
Form {
Button("hello") {
alertKind = .hello
}
Button("world") {
alertKind = .world
}
Button("state") {
print("kind: \(String(describing: alertKind))")
}
}
.alert(
"alert demo",
isPresented: $alertKind.bool(),
presenting: alertKind
) { kind in
switch kind {
case .hello:
Button("OK") { }
Button("NG") { }
case .world:
Button("OK") { }
}
} message: { kind in
switch kind {
case .hello:
Text("hello")
case .world:
Text("world")
}
}
}
}
SwiftUI経験がまだ浅いので、他に良い方法があるのかは分かっていませんが。
isPresented
のために、わざわざBool
のプロパティを持つ必要が無くなるので、割とスマートな実装になりそうと思いました。