[SwiftUI] iOS16以下でもonChange(of:initial:_:)が使いたい!
概要
SwiftUIで値の変更を監視する便利なメソッドonChange
スピークバディプロジェクト内ではGeometoryReaderと併用して、子ビューのframeを取得したりするのに使用しています!
iOS16以前のonChangeではViewの初期表示時(値変動前)にonChangeのクロージャ内の処理が走ることはありませんでした。
なので、よくこんなふうにonAppearと併用する形でコードを書いていました。
onAppear { action(value) }
.onChange(of: value, perform: action)
しかし、iOS17からonChangeにinitialというプロパティが追加されたことにより、このプロパティをtrueにすると初回表示時にもクロージャが呼ばれるようになります!
しかしながら、スピークバディは未だiOS17未満もサポートしています…
便利なものが出たのにいつまでもonAppearとの併用なんて嫌だ!
ということで以下のextensionを定義してみました。
コード紹介
実装
extension View {
@ViewBuilder func onChange<V: Equatable>(of value: V, initial: Bool, perform action: @escaping (_ newValue: V) -> Void) -> some View {
if #available(iOS 17.0, *) {
onChange(of: value, initial: initial) {
action($1)
}
} else if initial {
onAppear { action(value) }
.onChange(of: value, perform: action)
} else {
onChange(of: value, perform: action)
}
}
}
使用例
EmptyView()
.onChange(of: value, initial: true) { newValue in
// 値変更に伴う処理
}
余談
ちなみにiOS17以降のonChangeはinitialプロパティの他にクロージャの引数としてoldValueも取れるようになっています。
このoldValueをiOS17未満でも使用したい場合は、以下のように書くと再現できるようです!
EmptyView()
.onChange(of: value) { [value] newValue in
let oldValue = value
let newValue = newValue
}
これもextension化しちゃえば気軽に使えますね!
参考記事
めちゃめちゃ勉強になりました…🙇♂️
おわり
お読みいただきありがとうございます!
もしなにかのお役に立つことがございましたら、
♡を頂けますとすごく励みになります😊
この記事が気に入ったらサポートをしてみませんか?