作成中です。
Part8では、@Stateと@Bindingを解説していきたいと思います。
変数とは?
まず、@State、@Bindingを説明する前に、変数というの理解しておかないといけないので、変数から解説していきます。
変数というのは、var
がついている値のことです。イメージ的には値を入れる箱だと思ってください。
実は、前回、前々回のPartでも変数を書いています。Diceアプリでは、randomNumber
という変数を宣言して出目を入れていました。モーダル遷移を実装するときにはisShowThirdView
という変数を宣言して、遷移するかどうかの値を入れていました。
というように、変数はプログラミングにとってとても重要です。
もし、変数がなければ、「ボタンを押したらTextの文字を変える」というプログラムは書けません。
じゃあ、「ボタンを押したらTextの文字を変える」というプログラムを見てみましょう。
struct ContentView: View { @State var str = "Hello, world!" var body: some View { VStack { Text(str) .padding() Button(action: { str = "ハローワールド" }) { Text("ボタン") } } } }
この画面を表示すると、テキストと、ボタンが表示されます。
Textでstr
を表示しています。str
は、"Hello, world!"
なので、画面には「Hello, world」と表示されます。
ボタンを押すと、str
に"ハローワールド"
という文字列を代入(上書き)しています。それにより、画面に表示されているテキストが、「”ハローワールド”」に変わります。
というように、Textの中身をstr
という変数にしているため、このようにボタンを押したら、Textの文字を変えることができるのです。str
がなかったら実装できません。
図解するとこんな感じです。
@Stateとは?
SwiftUI開発での、変数には基本的に@Stateがついていると思います。
じゃあ、@Stateをつけるとどうなるのかというと、
- 値が変わったら、Viewがリロードされます。
- Structの中で値を変更することができます。
この2つの仕様が追加されます。
1. 値が変わったらViewがリロードされる
@Stateがついた変数をボタンなどで変更すると、Viewがもう一度読み込まれます。
以下の図解は、ボタンを押したときの読み込まれる処理の順番をあわらした図解です。
もし、@Stateがついていなかったら、ボタンを押したら、Viewの再描画は行われないので、Textの文字は変わりません。
2. Structの中で値を変更することができる
Swift言語のルール上、Struct
の中で変数の変更はできません。(使うことはできる)
Cannot assign to property: 'self' is immutable
と怒られてしまいます。
@Stateをつけると、このエラーは解消されます。
まとめると、@Stateは、structの中でプロパティを変更できるようし、変更するたびに再描画させるための修飾子です。
@Bindingとは?
次に@Bindingについて解説していきたいと思います。こちらは、プログラミング初心者にとっては、難しいと思うかも知れませんが、まずは、そんなこともできるんだなぁ程度で覚えてください。
@Bindingというのは一言で言うと、View間でのデータの共有ができる修飾子です。
画面Aと画面Bがあるとすると、画面Bで画面Aの@Stateを変更したいと言うときに、@Bindingを使います。
一番簡単な例は、モーダル表示の画面を閉じる処理なので、前回のPart7の画面遷移を復習しながら、@Bindingを使ってモーダル表示の画面を閉じる処理をやっていきましょう。
適当にPart8
とかでプロジェクトを作ってください。
Part8を選択してcommand + n
①SwiftUI Viewを選択
②Nextをクリック
①Save as:にNextView.swift
と入力
②Createをクリック
これでNextViewが作れました。
NextView
を以下のように変更しましょう。ただ画面をオレンジ色にしただけです。
struct NextView: View { var body: some View { ZStack { Color(.orange) Text("NextView") } } }
ContentViewを以下のように変更してください。
struct ContentView: View { @State var isShowNextView = false var body: some View { Button(action: { isShowNextView = true }) { Text("NextViewへ") } .sheet(isPresented: $isShowNextView) { NextView() } } }
実行してみると、このように画面遷移できるはずです。
Part7で解説しましたが、@Stateの解説をしたので、前回より深く理解できると思います。
11行目で、isShowNextView
というBool型(trueかfalseか)の@State
の変数を持ちます。
19行目の、.sheet(isPresented: $isShowNextView)
で、もしisShowNextView
がtrue
だったらNextView()
に遷移させるというコードを書いています。
最初に画面が表示されたときは、isShowNextView
がfalse
のため、20行目は実行されません。15行目で@StateのisShowNextView
をtrue
にすると、再描画され、20行目が実行されます。という仕組みになっています。
現状、下にスワイプすると画面を戻れますがボタンでも戻れるようにしましょう。まずはボタンを作ります。
NextView.swiftに、以下のように、VStackでTextを囲ってButtonを追記しましょう。
struct NextView: View { var body: some View { ZStack { Color(.orange) VStack { Text("NextView") Button(action: { print("ボタンが押されたよ") }) { Text("ボタン") } } } } }
画面を閉じるには、画面遷移と逆のことをしましょう。要は、isShowNextView
をfalse
にすると言うことです。ですが、isShowNextView
はContentViewで宣言されているので、NextViewでは使えません。
以下のようにCannot find 'isShowNextView' in scope
と言うエラーになります。
では、NextViewでも使えるようにしましょう。そこで@Bindingを使います。
NextViewに以下の変数を追加しましょう。
@Binding var isShowNextView: Bool
このようにやると、プレビューを表示させるコードでエラーになります。今回はプレビューはもう必要ないので削除しましょう。
command + bを押すとエラーがあるかどうかをチェックできます。現時点だと、ContentViewに以下のようにエラーが出ているはずです。
理由としては、NextViewで宣言した、@Bindingに値を渡していないからです。
①丸ぽちを押す
②Fixをクリック
そうすると以下のように、自動でNextViewで宣言した@Bindingが表示されます。
ここにContentViewのisShowNextView
を渡してあげます。
以下のように$をつけて記載してください。
NextView(isShowNextView: $isShowNextView)
NextView(isShowNextView: $isShowNextView)
変数名が同じなのでわかりづらいですが、NextViewのisShowNextView
に、ContentViewのisShowNextView
を入れています。
閉じる処理を入れましょう。ContentViewのisShowNextView
を渡すことができたので、NextViewでも使えるはずです。
以下のように、追記しましょう。
Button(action: { print("ボタンが押されたよ") isShowNextView = false }) {
これで、ボタンを押すと、閉じれるようになってるはずです。
これが、@Bindingの使い方です。他のViewの値をいじりたいときは、このように@Bindingを使います。次のPartでも@Bindingを使っていくので、何回も使って覚えていきましょう。