【Swift UI】TextFieldのキーボードを閉じる方法と@FocusStateの使い方

この記事からわかること
- SwiftUIでTextFieldでnumberPadを指定する場合
- キーボードを閉じることができない場合の解決法
- @FocusStateの使い方と閉じるボタンの自作方法
- 子ViewにあるTextFieldの閉じるボタンを実装する方法
- ビルドしたシミュレーターにキーボードを出現させる
- 閉じるボタンが表示されない問題の解決法
index
[open]
\ アプリをリリースしました /
Swift UIでアプリを開発中にTextField
の入力画面でキーボードをnumberPad
(数字のみ)にしたところ閉じることができなくなってしまいました。
また親Viewと子Viewに分けて作成していたところ、子ViewのTextField
に閉じるボタンを実装しようとしても表示されませんでした。
今回は「閉じるボタンの実装方法」と「子ViewにあるTextFieldへの閉じるボタンの実装方法」をまとめていきます。
TextFieldでnumberPadのみ発生する閉じれない問題
Swift UIではTextField
を使うと簡単に以下のような入力可能な要素を作成できます。

入力欄にフォーカスを当てるとキーボードが表示されますが、数字のみの入力にしたい場合は.keyboardType(.numberPad)
で数字キーのみに指定することができました。
しかし通常はEnterキー
の押下でキーボードは閉じられますが、数字キーのみの場合はEnterキー
がなく閉じることができなくなってしまいます。
解決策として閉じるボタンを自作で実装することでキーボードを閉じることができるようにしていきます。

閉じるボタンを自作方法
閉じるボタンを自作する際に重要なポイント
- フォーカスを操作できるようにする
- @FocusState
- toolbarとToolbarItemGroup
TextField
のキーボードが出現するのは対象のTextField
にフォーカスが当たっている時です。TextField
のフォーカスは.focused(変数)
で取得、操作することが可能になっています。(Bool値
)
@FocusStateの使い方
.focused(変数)
に渡す変数は@FocusStateが付与されていないといけません。
@FocusState
とはiOS15以降(Swift5.1)から使えるようになったProperty Wrapper(プロパティラッパー)の1つです。プロパティラッパーはプロパティに対する操作や処理をカプセル化して定義することで特定のキーワードを付与するだけで任意の動作や挙動を行わせることができる便利な機能です。
その中でも@FocusState
はその名前の通り、TextFieldなどの要素のフォーカス制御を可能にしています。
@FocusStateを付与したコード
しかしこれではまだボタンの実装はできていません。実際のボタンは.toolbar
で実装していきます。
toolbarとToolbarItemGroup

ボタンを実装するにはtoolbar
モディファイアのToolbarItemGroup
内に実装していきます。
閉じるボタンを実装したコード
.focused
をつけてフォーカスを制御できるようにしたTextField
にtoolbar
モディファイアを追加します。中にはToolbarItemGroup
を定義し、引数のplacement
は.keyboard
を指定します。
ToolbarItemGroup
の中にはButton
を定義し、そのアクション部分にフォーカスが外れる処理(falseを格納)します。
Button
の上側にSpacer()
を入れることで閉じるボタンを右寄せにすることができます。
これで数字のみのキーボードに閉じるボタンを実装することができました。
Stackの中に複数のTextFieldがある場合
TextField
が複数あり、○Stack
で囲んでいる場合はtoolbar
モディファイアは○Stack
に指定してもOKです。
フォーカスを制御している変数はTextField
が複数あっても1つで問題ありませんでした。toolbar
モディファイアを特定の1つのTextField
に指定しても期待通りの動作をしましたが、可読性の観点から囲んでいるStackに当てるのがおすすめです。
子ViewにあるTextFieldへの閉じるボタンの実装方法
解決策
親Viewにfocusedとtoolbarを実装する
先ほどのように1つのビュー内で入れ子になっている場合はその一番上の要素の当てるだけでよかったですが、親ビューから子ビューを呼び出している場合は閉じるボタンの実装に注意が必要です。
子ビュー側に@FocusState
と「閉じるボタン」を実装して親ビューから呼び出してみたところ数字のみのキーパッドに閉じるボタンどころかツールバー自体が表示されませんでした。
閉じるボタンが表示されなかったコード
子ビュー
親ビュー
これを解決するためには親ビュー側にフォーカスの制御(@FocusState
)とツールバーへの閉じるボタンを追加を記述しないといけないようです。
解決したコード
子ビュー
親ビュー
ビルドしたシミュレーターにキーボードを出現させる
プレビューではキーボードが表示されないのでシミュレーターを起動させて確認する必要があります。

ツールバーにある ボタンをクリックしてシミュレーターを起動させてTextField
にフォーカスを当ててもキーボードが出ない場合もあります。
解決するには「Simulator」>「I/O」>「Keyboard」>「Toggle Software Keyboard」をクリックするとフォーカスが当たった時にキーボードが出現するようになります。

TextFieldの使い方
理解を深めるためにTextField
の使い方と注意点をまとめておきます。
TextFieldを使用するポイント
- 入力値はバインディングされた変数に格納される
- 格納される値はString型になる
- 引数:titleKeyには入力内の文字を指定
- textFieldStyleモディファイアで見た目を変更可能
- keyboardTypeモディファイアで表示されるキーボードを指定可能
構文
使用例
カスタマイズした枠線をつける方法
TextFieldに枠線を付けるには先ほど紹介したtextFieldStyle(RoundedBorderTextFieldStyle())
を指定することで「角に丸みを帯びた枠線」を付与することができます。

しかし色をつけた枠線を付ける方法は今のところないので要素の上に要素を重ねることのできるoverlay
モディファイアを使用して枠線を作成していきます。

閉じるボタンが表示されない問題の解決法
以下のようにsheet
モディファイアを使用して表示させたビューではなぜか「閉じるボタン」が表示されませんでした。それだけでなくナビゲーションタイトルも表示されませんでした。sheet
モディファイアを使用したビューではナビゲーションバー(ツールバー)が表示されないようです。
これを解決するには以下のようにsheet
モディファイアで渡すビューもNavigationStack
で囲むことで正常に表示されるようになりました。(この方法が正しいのかは分かりませんが...)
解決策(NavigationStackで囲むだけ)
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。