よっしーブログ

iOSエンジニアやってます。SwiftUI勉強中です。

@Bindingについてサンプルで理解する

こんにちは。iOSエンジニアをしております。よっしーです。
SwiftUIはUIkitと違って苦戦しています。。
勉強した内容をまとめていきたいと思っています。

はじめに

今回も引き続きSwiftUIのpropertyWrapper編です。
前回は@Stateについて書きました。

yosshi-ios.hatenablog.com

@Bindingもとても重要なので、理解できるようにサンプルを用いて説明しようと思います。

@Bindingとは

@Bindingを付与すると、別のビュー同士の変数を紐づけることができる。親のプロパティを子のViewで変えたい時に使用する。

サンプル実装

担当者チェックのボタンを押下すると状態によって画像が切り替わるという簡単なアプリです。

BindinglsCheckedView(子View)

BindinglsCheckedViewはisCheckedプロパティを保持していてボタン押下時に画像と色を切り替えます。
親から渡されるプロパティを紐付けしたい為@Bindingで宣言します。

struct BindinglsCheckedView: View {
    
    /// 親から渡されるプロパティ
    @Binding var isChecked: Bool
    
    var body: some View {
        
        Button(action: {
            // ボタンを押したらプロパティ更新
            isChecked.toggle()
        }) {
            // isCheckedによって画像を変える
            // isCheckedによってforegroundColorを変える
            Image(systemName: isChecked ? "person.fill.checkmark" : "person")
                .foregroundColor(isChecked ? .blue : .gray)
                .scaleEffect(2.0)
        }
    }
}
ContentView(親View)

親ビュー内に@StateとしてisCheckedPersonがfalseとして定義されています。
BindingでisCheckedPersonをBindinglsCheckedView(子View)
に渡しています。渡すときに、$をつけて渡します。

struct ContentView: View {
    
    @State var isCheckedPerson = false
    
    var body: some View {
                
        HStack {
            Text("担当者チェック")
            
            // 子のビューの呼び出しと紐付けるプロパティを渡す
            BindinglsCheckedView(isChecked: $isCheckedPerson)
        }
    }
}

応用

担当チェックのボタンをもう一つ用意し、両方押下したら
「全員チェック済み」のTextを表示します。
それ以外の場合は「チェック待ち」のTextを表示します。

ContentViewにisCheckedPerson1の他に、isCheckedPerson2を用意しそれを新たに用意したBindinglsCheckedView(子View)に渡し紐付けを行います。
紐付けを行ったプロパティ二つを監視し、状態によってTextの表示を変えます。以下が全ソースです。

/// 親View
struct ContentView: View {
    
    @State var isCheckedPerson1 = false
    @State var isCheckedPerson2 = false
    
    var body: some View {
                
        VStack {
        
            HStack {
                Text("担当者1のチェック")
                
                // 子のビューの呼び出しと紐付けるプロパティを渡す
                BindinglsCheckedView(isChecked: $isCheckedPerson1)
            }
            
            HStack {
                Text("担当者2のチェック")
                
                // 子のビューの呼び出しと紐付けるプロパティを渡す
                BindinglsCheckedView(isChecked: $isCheckedPerson2)
            }
            
            // 子と紐付けた親プロパティを監視
            if isCheckedPerson1 && isCheckedPerson2 {
                Text("全員チェック済み").foregroundColor(.blue)
            } else {
                Text("チェック待ち").foregroundColor(.red)
            }
            
        }
    }
}

/// 子View
struct BindinglsCheckedView: View {
    
    /// 親から渡されるプロパティ
    @Binding var isChecked: Bool
    
    var body: some View {
        
        Button(action: {
            // ボタンを押したらプロパティ更新
            isChecked.toggle()
        }) {
            // isCheckedによって画像を変える
            // isCheckedによってforegroundColorを変える
            Image(systemName: isChecked ? "person.fill.checkmark" : "person")
                .foregroundColor(isChecked ? .blue : .gray)
                .scaleEffect(2.0)
                .frame(width: 50, height: 50)
        }
    }
}

まとめ

@Bindingを付与すると別のビュー同士の変数の紐づけを行うことが出来る。親Viewからは渡すときには$をつけて渡す

次回は@ObservedObjectを書きたいと思っています。
間違っている点等ございましたら、教えていただけると助かります。

参考リンク

Apple Developer Documentation

【SwiftUI】@Bindingの使い方を徹底解説 | iOS-Docs

【Swift UI】@Bindingの意味と使い方とは?親と子の構造体