【SwiftUI】TextField を firstResponder にする

2021年1月28日

SwiftUI の TextField で例えばボタンを押した時、キーボードが出て TextField を入力状態にするのにはどうすれば良いか多少詰まりました。UITextField では becomeFirstResponder というのがあったと思いますが SwiftUI の TextField では使用出来ないようです。

UIViewRepresentable の実装

という事で UIViewRepresentable で UI TextField を SwiftUI で使えるようにしていきます。それを becomeFirstResponder する事にします。 UIViewRepresentable は公式のチュートリアルでも使われていたので色々な記事で使い方が書かれていると思います。

import SwiftUI
struct CustomizedUITextField: UIViewRepresentable {
    class Coordinator: NSObject, UITextFieldDelegate {
        @Binding var text: String
        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<CustomizedUITextField>) -> UITextField {
        let textField = UITextField(frame: .zero)
        textField.delegate = context.coordinator
        return textField
    }
    func makeCoordinator() -> CustomizedUITextField.Coordinator {
        return Coordinator(text: $text)
    }
    func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<CustomizedUITextField>) {
        uiView.text = text
        if isFirstResponder {
            uiView.becomeFirstResponder()
        }
    }
}
extension UIApplication {
    func closeKeyboard() {
        sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
    }
}

こんな感じで isFirstResponder というフラグを持っておいてそれによって becomeFirstResponder していきます。またここにキーボードを下げるための closeKeyboard を実装しておいて後で画面がタップされた時などに呼ぶ様にします。

View

先ほど実装した UITextField をラップした CustomizedUITextField とSwiftUI の TextFieldを両方置いて比較してみます。ボタンが押された際に TextField が表示されて CustomizedUITextField の方はそれと同時に入力可能状態になりカーソルが表示されます。

import SwiftUI
struct TestView2: View {
        
    @State var showTextField:Bool = false;
    @State private var name = ""
    
        var body: some View {
            VStack {
            
                Button(action: {
                    self.showTextField.toggle()
                }){
                    Image(systemName:"rectangle.and.pencil.and.ellipsis")
                }
                
                if showTextField != false {
                    CustomizedUITextField(text: $name, isFirstResponder: true)
                        .frame(width: 200, height: 30)
                        .border(Color.red, width: 1)
                        .padding()
                        
                }
                
                if showTextField != false {
                    TextField("", text: $name)
                    .frame(width: 200, height: 30)
                    .border(Color.red, width: 1)
                    .textFieldStyle(RoundedBorderTextFieldStyle())
                }
            }.onTapGesture {
                UIApplication.shared.closeKeyboard()
            }
            
    }
}

onTapGesture で先ほどの closeKeyboard も呼んでおきます。

これで終了。以下の様に動作します。 上の TextField は表示されると同時に入力状態になります。

学習書籍

このiPhoneアプリ開発入門ノートってやつ SwiftUI バージョンのもあるんですね。前にこのシリーズ読んでました。なかなかわかりやすかったです。


詳細!SwiftUI iPhoneアプリ開発入門ノート iOS 13+Xcode 11対応【電子書籍】[ 大重美幸 ]

他にも参考にしたい書籍をいくつかピックアップしておきます。


SwiftUI 徹底入門 [ 金田 浩明 ]

SwiftUIではじめるiPhoneアプリプログラミング入門 [ 大津 真 ]

iOS/macOS UI フレームワークSwiftUIプログラミング [ 掌田津耶乃 ]