シミュレーターでの入出力
これまでのサンプルで入力欄での入力を利用してきました。今回はプログラムの処理だけでなく、実際にアプリを使って入力するという動作に注目した処理について学んでみましょう。
シミュレーターでソフトウェアキーボードを使う
シミュレーターで動作したアプリで入力を行うときには、次の2つの方法があります。
・Macのキーボードでそのまま入力
・シミュレーター内のソフトウェアキーボードを利用して入力
既定ではMacのキーボードが使えるので、そのままMacのキーボードで入力して動作確認を行なっている場合がほとんどです。
シミュレーターでソフトウェアキーボードを使うためには、シミュレーターを立ち上げた後に、
メニューバーの「I/O」→「Keyboard」→「Toggle Software Keyboard」を選択してチェックを入れます。
「Toggle Software Keyboard」にチェックを入れると、アプリで入力を行う場合にソフトウェアキーボードが起動されます。
ただし、ソフトウェアキーボードを閉じる処理がないので、このままソフトウェアキーボードが表示され続けることになってしまいます。
ソフトウェアキーボードを閉じる処理を作成しましょう。
ソフトウェアキーボードと動作を管理するクラス
ソフトウェアキーボードは、UI単位の管理ではなく、アプリ全体を制御するUIApplicationというクラスで管理されます。
https://developer.apple.com/documentation/uikit/uiapplication/
UIApplicationクラスは、アプリ全体を管理しています。言い換えると、アプリの起動中はUIApplicationクラスのインスタンスもアプリを管理するために動いている、ということです。
ですので、UIApplicationクラスを利用する場合は、インスタンスでオブジェクトを作成するのではなく、起動中のUIApplicationクラスのインスタンスを利用することになります。
UIApplicationのオブジェクトを参照する際には、UIApplicationクラスのプロパティである「shared」を利用します。プロパティとは、クラスの状態を参照するもので、sharedプロパティでは、UIApplicationオブジェクトそのものを参照できます。
https://developer.apple.com/documentation/uikit/uiapplication/1622975-shared
プログラムの中からUIApplicationオブジェクトを参照するには次の書式でsharedプロパティを利用してください。
UIApplication.shared
また、アプリでソフトウェアキーボードの表示は、UIが入力状態にあるときだけです。UIが入力状態にない場合は、ソフトウェアキーボードは表示されません。
このUIが入力状態にあるか/ないかを管理するのは、UIResponderクラスです。
https://developer.apple.com/documentation/uikit/uiresponder
UIResponderクラスの「UIを入力状態でなくす」という処理は、resignFirstResponderメソッドで実行できます。
https://developer.apple.com/documentation/uikit/uiresponder/1621097-resignfirstresponder
Swiftのようにオブジェクトの相互作用で処理を作成するプログラムでは、このように各動作を管理するクラスが分かれており、そのクラス同士を組み合わせた処理を行う必要があります。
何段階にも分かれてますが、最終的にはアプリを管理するUIApplicationオブジェクトで、UIの入力状態を管理するUIResponderクラスの入力状態をなくすresignFirstResponderメソッドを実行すれば、ソフトウェアキーボードを非表示にする処理ができそうです。
ソフトウェアキーボードを閉じる処理を作成する
サンプルでボタンを押したときにソフトウェアキーボードを閉じる処理を実装してみます。
UIApplicationクラスには、sendActionメソッドというUIApplicationクラスでアプリ全体の処理として他クラスのメソッドを実行できる仕様があります。
https://developer.apple.com/documentation/uikit/uiapplication/1622946-sendaction/
func sendAction(_ action: Selector, to target: Any?, from sender: Any?, for event: UIEvent?) -> Bool
書式を確認すると、「Selector(セレクタ)」の引数があります。セレクタとは、メソッドを引数とするという意味です。
つまり、sendActionメソッドでUIResponderクラスのresignFirstResponderメソッドを引数にすることで、UIApplicationクラスでソフトウェアキーボードを閉じる処理を行うことができると考えられます。
サンプルのコードを次のように編集してください。
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) UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) } .disabled(!self.buttonEnabled) Text(self.inputText) .font(.title) .padding() } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
ボタンを押したときに、「UIApplication.shared」で参照したUIApplicationオブジェクトでsendActionメソッドを実行します。引数のセレクタとして「UIResponder.resignFirstResponder」としてUIの入力状態をなくすUIResponderクラスのresignFirstResponderメソッドを指定しています。
このまま書くと、メソッドをそのまま実行するという意味になってしまいますので「#selector( )」で囲ってセレクタであることを明記します。
またsendActionメソッドの「to」「from」「for」に関してはメソッド実行の詳細を指定する引数です。ここでは、そこまでの詳細な処理は必要ありませんので「nil(何もない)」のオブジェクトを指定しています。
シミュレーターでサンプルを実行すると、ボタンを押したときにキーボードを閉じる動きを確認できます。
今回のサンプルでは、ソフトウェアキーボードを閉じるという動作のために、複数のクラスとメソッドを利用しました。
Swiftのオブジェクトの関連性で処理を作成する、という特徴を実感してアプリの作成を進めてください。