UIViewでテキスト入力を行う(UIKeyInput)

前回の記事の続きです。

前回のテキストを描画した画面に、キーボードからテキストを入力を行う方法についてまとめます。今回も前回と同様にSwiftUI + CoreText (CoreTextSwift) を利用します。

テキスト入力

テキストを入力するには、キャレットの表示や文字を挿入できるようにする必要があります。

UIKeyInputプロトコルを実装すると、システムキーボードを表示させ文字入力を行えるようになります。

また、日本語など入力するにはIME APIを通してやり取りできる必要があります。そのためにはUITextInputプロトコルを実装します。

UIKeyInputの実装

UITextInputは実装すべきメソッドが多く実装が複雑になるため、ひとまず簡単なテキスト入力だけ行えるように、UIKeyInputプロトコルを実装します。

今回はtextが可変となるため、Bindingの変数textを受け取るようにします。

struct ContentView: View {
    @State private var text = ""
    var body: some View {
        VStack() {
            CoreTextView(text: $text)
        }
    }
}

UIViewRepresentableは前回とほぼ同様ですが、becomeFirstResponder()を呼び出すようにしています。これによりファーストレスポンダとしてテキスト入力を処理できるようになります。

struct CoreTextView: UIViewRepresentable {
    @Binding var text: String

    func makeUIView(context: Context) -> UICoreTextView {
        let view = UICoreTextView(text: $text)
        view.becomeFirstResponder()
        view.isOpaque = false
        return view
    }

    func updateUIView(_ uiView: UICoreTextView, context: Context) {
    }
}

前回のUICoreTextViewがBinding変数textを保持できるようにします。今回はdidSetで変数が変更されるたびにsetNeedsDisplay()を呼び出すようにします。

また、上記で設定したbecomeFirstResponder()が有効になるように、canBecomeFirstRespondercanResignFirstResponderをtrueに設定します。

class UICoreTextView: UIView {
    @Binding var text: String {
        didSet {
            self.setNeedsDisplay()
        }
    }
    
    init(text: Binding<String>) {
        self._text = text
        super.init(frame: .zero)
    }

    required init?(coder: NSCoder) {
        fatalError()
    }

    override func draw(_ rect: CGRect) {
        // 前回と同じのため省略
    }

    override var canBecomeFirstResponder: Bool {
        return true
    }

    override var canResignFirstResponder: Bool {
        return true
    }
}

次にUIKeyInputを実装します。

extension UICoreTextView: UIKeyInput {
    var hasText: Bool {
        return self.text.count > 0
    }

    func insertText(_ text: String) {
        self.text.append(text)
    }

    func deleteBackward() {
        if self.text.count > 0 {
            self.text.removeLast()
        }
    }
}

これにより基本的なテキスト入力ができるようになりました。

参考

参考1: Lower Level Text-Handling Technologies
参考2: UIViewとUITextInputで作る縦書きのTextView iOSDC Japan 2018

今回、記載しなかったUITextInputの実装は以下のコード(リポジトリ)が参考になりそうです。





最後まで読んでいただきありがとうございます。 他の記事はこちらからどうぞ → https://note.com/sat0b3ee/