目的
SwiftUI では Property Wrappers により画面要素やデータの変化を簡単に画面に反映できます。ここでは、Property Wrappers の変化に応じて、View の構造体に実装した処理(メソッド)を実行する方法を記載します。
*ビジネスロジックはViewModelなどに記載することが基本だと思いますが、画面の最上部までスクロールする
とか画面を閉じる
などの処理を簡単に実装したいときに利用します。
実装例
@State
プロパティの変更を検知してメソッドを実行
Viewファイル内で、@State
とそれに接続した@Binding
プロパティを実装し、@Binding
プロパティの{set}
でメソッドを呼び出します。
// MARK: TabItemのタップを検知し、メソッドを実行する例
struct contentView: View {
@State var tab: Int = 0
var body: some View {
let tabBinding = Binding<Int>(get: {
self.tab
}, set: {
if $0 == self.tab {
self.method()
}
self.tab = $0
})
TabView(selection: tabBinding) {
TabView_1().tag(0)
TabView_2().tag(1)
}
}
private func method() {
if self.tab == 0 { }
}
}
参考:3 Ways to React to @State Changes in SwiftUI
ViewModel側の処理結果に応じてViewを閉じる
ここではモーダル遷移の例を示しますが、プッシュ遷移でも同様です。参考にしたサイトにプッシュ遷移の実装例があります。
// MARK: Child画面をChildのViewModelの指示で閉じる
struct Parent_View: View {
@State var showChild: Bool = false
var body: some View {
Button(action: {
self.showChild = true
}, label: { Text("Go_Child") })
Spacer().frame(height: 0).sheet(isPresented: $showChild) {
let vm = Child_ViewModel(showChild: $showChild)
Child_View(viewModel: vm)
}
}
}
struct Child_View: View {
@ObservedObject var viewModel: Child_ViewModel
init(viewModel: Child_ViewModel) {
self.viewModel = viewModel
}
var body: some View {
// something
}
}
class Child_ViewModel: ObservableObject {
// これは@Publishedで宣言してもいい(参考にしたサイトは@Publishedを使用していた)
@Binding var showChild: Bool
init(showChild: Binding<Bool>) {
self._showChild = showChild
}
func dismiss() {
self.showChild = false
}
}