複数のUI間の連携
データバインディングを利用するとコード内の変数と画面上のUIを接続できます。この仕組みを利用すると、変数とUIという1対1の関係以上の処理を行うこともできます。簡単なサンプルを作成して、変数とUIの連携の例を確認してみましょう。
入力値を別のUIに反映する
入力欄に入力した文字列を画面に表示するサンプルを作成してみます。前回のサンプルのボタンの下に、文字列を表示する「Text」を配置してください。
自動的に追記されたコードを確認します。
import SwiftUI
struct ContentView: View {
var subject: String = "Hello, Swift"
var message: String = "ボタンを押しました"
@State var inputText: String = "テキスト入力です"
var body: some View {
VStack {
TextField("入力してください", text: $inputText)
.font(.title)
.textFieldStyle(.roundedBorder)
.padding()
Button("Button") {
print(self.inputText)
}
Text("Placeholder")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Textに表示する値をバインディング変数「inputText」にします。さらにfontメソッドで文字を大きく、paddingメソッドで余白を設けます。
import SwiftUI struct ContentView: View { var subject: String = "Hello, Swift" var message: String = "ボタンを押しました" @State var inputText: String = "テキスト入力です" var body: some View { VStack { TextField("入力してください", text: $inputText) .font(.title) .textFieldStyle(.roundedBorder) .padding() Button("Button") { print(self.inputText) } Text(self.inputText) .font(.title) .padding() } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
プレビュー画面で入力欄の値が「Text」に反映されることが確認できます。シミュレーターを起動してアプリの動きでも確認してみましょう。
入力欄に入力した文字列が、ボタンの下のテキストにリアルタイムで反映されることがわかります。
「入力欄への入力」→ 「バインディング変数」→(プログラム内の処理)→「テキストへの反映」といった処理の流れが確認できます。
入力値で別のUIを制御する
iOSアプリでは、画面からの入力に応じて次に行うアプリの動作を変える、というUIの制御はよく行われます。このUIの制御の例をサンプルで確認してみましょう。
入力欄の入力が5文字以上の場合のみボタンを押すことができる、という処理を作成してみます。
最初にBool型のバインディング変数「buttonEnabled」を宣言し、元々のinputText変数の値を空にします。
import SwiftUI struct ContentView: View { var subject: String = "Hello, Swift" var message: String = "ボタンを押しました" @State var inputText: String = "" @State private var buttonEnabled: Bool = false var body: some View { VStack { TextField("入力してください", text: $inputText) .font(.title) .textFieldStyle(.roundedBorder) .padding() Button("Button") { print(self.inputText) } Text(self.inputText) .font(.title) .padding() } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
変数の値が入っていないことを「空(から)」と呼びます。バインディング変数「inputText」を空にしたことで、プレビュー画面の表示もなくなったことを確認してください。
Bool型のバインディング変数「buttonEnabled」は、trueかfalseのどちらかの値を持ちます。これでボタン押下の制限をかけます。宣言時は false の値を代入しています。
次に、入力欄に入力された内容で、変数「buttonEnabled」の値を変える処理を作成します。
import SwiftUI struct ContentView: View { var subject: String = "Hello, Swift" var message: String = "ボタンを押しました" @State var inputText: String = "" @State private var buttonEnabled: Bool = false var body: some View { VStack { TextField("入力してください", text: $inputText) .font(.title) .textFieldStyle(.roundedBorder) .padding() .onChange(of: self.inputText) { // 5文字以上でボタン押下可能 if ($0.count >= 5) { self.buttonEnabled = true } else { self.buttonEnabled = false } } Button("Button") { print(self.inputText) } Text(self.inputText) .font(.title) .padding() } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
UIの入力が変更されたときに実行される onChange メソッドを利用して、入力欄への入力が行われたときの処理を定義しています。
onChange メソッドは入力系のUIで共通して利用できるメソッドで次の書式で定義されています。
https://developer.apple.com/documentation/swiftui/view/onchange(of:perform:)
onChange(of: 入力値) { 入力値に変更があった場合の処理 $0 で入力値が渡される }
サンプルでは入力欄の入力値が変更された場合に処理を行いたいので、TextFieldのインスタンスにでonChangeメソッドを実行するように「.」で繋げてonChange メソッドを記述します。
入力欄の入力値はバインディング変数「inputText」です。onChangeメソッドの入力値には、「self.inputText」を指定します。
onChangeの後ろのブロックには、入力値が「$0」の書式で得られます。String型のオブジェクトでは、countプロパティで文字列の長さが参照できます。文字列の長さが5文字以上の場合に、変数「buttonEnabled」の値を true にする処理を作成しています。
文字列が5文字以上であるかの判定は if else 文で行っています。if else 文の書式は次の通りです。
if ( 条件式 ) { // 条件式に合致する場合の処理 } else { // 条件式に合致しない場合の処理 }
サンプルのように、条件に合う/合わない場合の処理を分岐したいときに利用します。
コード内の「//」で始まる行はコメントです。コメントとはコードに影響しない記述のことで、サンプルのようにメモ的に処理の内容を記述するときに利用されます。
最後に、変数「buttonEnabled」がtrueの場合にボタンを押下可能に、falseの場合にボタンを押下不可能にする処理を作成します。
import SwiftUI struct ContentView: View { var subject: String = "Hello, Swift" var message: String = "ボタンを押しました" @State var inputText: String = "" @State private var buttonEnabled: Bool = false var body: some View { VStack { TextField("入力してください", text: $inputText) .font(.title) .textFieldStyle(.roundedBorder) .padding() .onChange(of: self.inputText) { // 5文字以上でボタン押下可能 if ($0.count >= 5) { self.buttonEnabled = true } else { self.buttonEnabled = false } } Button("Button") { print(self.inputText) } .disabled(!self.buttonEnabled) Text(self.inputText) .font(.title) .padding() } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
ボタン押下可否の処理も入力系UIに共通して利用できる disabled メソッドを利用します。
https://developer.apple.com/documentation/swiftui/view/disabled(_:)
disabled(_ disabled: 不可にする場合はtrue / 可能にする場合はfalse )
Bool型の変数では、変数の頭に「!」をつけると逆の値になります。
変数「buttonEnabled」は入力欄の文字列の長さが5文字以上の場合に true になります。このときにボタンを押せるようにしたいので、disabledメソッドに false を渡せるように変数の頭に「!」をつけた「!self.buttonEnabled」をメソッドの引数にしています。
変数「buttonEnabled」の値とdisabledメソッドの引数の値が逆になる点に注意してください。
シミュレーターを起動してアプリを実行すると、5文字以上入力したときだけボタンが押せることがわかります。
4文字まではボタンの文字色が灰色で押せません。
入力が5文字を超えるとボタンの文字が青になって押せるようになります。
ボタンを押した後は、コンソールに入力欄の文字が出力されることも確認できます。
「入力欄への入力」→ 「バインディング変数」→(プログラム内の処理)→「別のバインディング変数」→「ボタンのdisabledメソッド」→「ボタン押下可否」といった処理の流れが確認できます。