■Bindingとは
"A property wrapper type that can read and write a value owned by a source of truth."
※引用:Apple Developer Documentation
「信頼できる情報源が所有する値の読み取りと書き込みが可能なプロパティラッパータイプ」です。
・・・?
■サンプルコードを使って説明
以下の記事で使ったサンプルコードを引き続き使用して説明してみます。
該当コード
import SwiftUI
struct ContentView: View { @State var buttonTitle = "Button sample" var body: some View { VStack { Button(action: { self.buttonTitle = "Button tapped!" }) { Text("\(buttonTitle)") .frame(width: 200, height: 70, alignment: .center) .foregroundColor(Color.white) .background(Color.blue) .cornerRadius(10, antialiased: true) } } } }
ボタンを選択すると以下の画像のように表示が切り替わります。
では、仮に同じボタンを2つ縦並びに表示して、それぞれ選択状態を管理するにはどのようにすればよいでしょうか。
単純にButtonを1つ増やしてみます。
import SwiftUI struct ContentView: View { @State var topButtonTitle = "Button sample" @State var bottomButtonTitle = "Button sample" var body: some View { VStack { Button(action: { self.topButtonTitle = "Button tapped!" }) { Text("\(topButtonTitle)") .frame(width: 200, height: 70, alignment: .center) .foregroundColor(Color.white) .background(Color.blue) .cornerRadius(10, antialiased: true) } .padding() Button(action: { self.bottomButtonTitle = "Button tapped!" }) { Text("\(bottomButtonTitle)") .frame(width: 200, height: 70, alignment: .center) .foregroundColor(Color.white) .background(Color.blue) .cornerRadius(10, antialiased: true) } } } }
確かに、これでもそれぞれのボタンの選択状態を管理することができますが、ボタンの仕様が共通なのであれば、わざわざ似たような実装を繰り返すのではなく、ボタンのViewを2度インスタンス化してContentViewに表示したほうが無駄な実装を減らすことができそうです。以下のようなイメージです。
※以下のコードはエラーになるので、あくまでボタンを共通化したらよさそうというイメージだけ伝えたく記載しています。
import SwiftUI struct ContentView: View { var body: some View { // SampleButtonを2度インスタンス化して縦並びで表示 VStack { SampleButton() .padding()
SampleButton() } } } // Buttonの仕様が実装されたView struct SampleButton: View { @State var isTapped: Bool var body: some View { Button(action: { self.isTapped = true }) { Text(isTapped ? "Button tapped!" : "Button sample") .frame(width: 200, height: 70, alignment: .center) .foregroundColor(Color.white) .background(Color.blue) .cornerRadius(10, antialiased: true) } } }
ここで問題となるのが、「上部のボタンと下部のボタンでそれぞれボタンの選択状態を管理するにはどのようにすればよいか」です。
そこで登場するのが@Bindingです。@Bindingを使うと、他の構造体の変数と@Bindingをつけた変数を結びつけます(Binding=結びつけるという意味)。結びついた他の構造体の変数が状態を管理することで、インスタンスごとに状態を管理することができます。
以下が@Bindingを使って上部のボタンと下部のボタンでそれぞれボタンの選択状態を管理しているコードです。サンプルはButtonを使って説明しましたが、実際の使用ケースとしては、ログイン画面のIDとパスワードを入力するためのTextFieldなどが考えられます。
import SwiftUI struct ContentView: View { // 追加 // 上部のボタンの選択状態を管理する変数 @State var isTopButtonTapped = false // 追加 // 下部のボタンの選択状態を管理する変数 @State var isBottomButtonTapped = false var body: some View { VStack { // 追加 // インスタンス化する際に引数にisTopButtonTappedを指定したことで、 // 構造体SampleButtonの変数isTappedの状態と、isTopButtonTappedの状態が結びつく // つまり、このインスタンスにおいてはisTappedがtrueになればisTopButtonTappedもtrueとなる SampleButton(isTapped: $isTopButtonTapped) .padding() // 追加 // インスタンス化する際に引数にisBottomButtonTappedを指定したことで、 // 構造体SampleButtonの変数isTappedの状態と、isBottomButtonTappedの状態が結びつく // つまり、このインスタンスにおいてはisTappedがtrueになればisBottomButtonTappedもtrueとなる SampleButton(isTapped: $isBottomButtonTapped) } } }
■参考リンク