はじめに
SwiftUIにはTextFieldというテキストを入力するためのViewがデフォルトで準備されているのですが、viewをロードした段階ですでにTextFieldにフォーカスが当てられているような方法が見つからなかったので、今回はその実装をしてみました。
したいこと
下の画像のように、viewが読み込まれた時にデフォルトでTextFieldにフォーカスが当てられているようにしました。
また、本記事では説明しませんが、今回はクロスワードアプリを作っていたので、文字入力がされると、次のブロックへ移動して新たなTextFieldにフォーカスが当たるようにしました。
実装
import SwiftUI
struct FocusableTextField: UIViewRepresentable {
class Corrdinator: NSObject, UITextFieldDelegate {
@Binding var text: String
var didBecomeFirstResponder = false
init(text: Binding<String>) {
_text = text
}
func textFieldDidChangeSelection(_ textField: UITextField) {
text = textField.text ?? ""
}
}
@Binding var text: String
var isFirstResponder: Bool = false
func makeUIView(context: UIViewRepresentableContext<FocusableTextField>) -> UITextField {
let textField = UITextField(frame: .zero)
textField.delegate = context.coordinator
return textField
}
func makeCoordinator() -> FocusableTextField.Corrdinator {
return Coordinator(text: $text)
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<FocusableTextField>) {
uiView.text = text
if isFirstResponder && !context.coordinator.didBecomeFirstResponder {
uiView.becomeFirstResponder()
context.coordinator.didBecomeFirstResponder = true
}
}
}
上の処理の流れとしては以下の感じです。
- FocusableTextFieldというUIViewRepresentableプロトコルを継承したstructを作成します。このUIViewRepresentableというのはSwift UIとUIKitの橋渡しを行なってくれます。
- makeUIViewというメソッドで新しいUITextFieldを生成し。UITextFieldDelegateをCoordinatorに割り当てることでテキストフィールドの状態を監視しています。
- updateUIViewでフォーカスの処理を行っています。ここではisFirstResponderやdidBecomeFirstResponderの状態を監視して、必要に応じてuiView.becomeFirstResponder()を呼び出します。ここで使用しているbecomeFirstResponder()はUILitのメソッドで、呼び出されるとそのviewが一番はじめに入力操作を受け付けるようになるため、今回したかったことが実現されます。
最後に
色々調べてみても、フォーカスの検知などの記事しか見つからなかったため、今回は自作でデフォルトでフォーカスが当てられるTextFieldの実装を行なってみました。もしSwift UIでそのようなViewがデフォルトで用意されていたり、良い方法をご存知の方いれば教えていただけると幸いです。
ではここまで読んでくれてありがとうございました^^
参考文献