画像のようにキーボードの上にツールバーがのったUIを作成します。
要件は以下のとおりです。
- キーボードの上にツールバーが表示する
- ツールバーのボタンをタップするとキーボードが閉じる
- タップ時にログに入力した文字列を表示する
UITextView
をUIViewRepresentable
に準拠させる実装を行います。
makeUIView
この関数でUITextView
を返します。
また、UIToolbar
を上部にのせます。
UITextViewRepresentable.swift
struct UITextViewRepresentable: UIViewRepresentable {
@Binding var text: String
private let textView = UITextView()
func makeUIView(context: Context) -> UITextView {
textView.delegate = context.coordinator
textView.autocapitalizationType = .none
textView.autocorrectionType = .no
textView.keyboardType = keyboardType
let toolbar = UIToolbar(frame: CGRect(x: .zero, y: .zero, width: textView.frame.size.width, height: 44))
let spacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let doneButton = UIBarButtonItem(
title: "Done",
style: .done,
target: context.coordinator,
action: #selector(context.coordinator.onTapDone(_:))
)
toolbar.setItems([spacer, doneButton], animated: true)
textView.inputAccessoryView = toolbar
return textView
}
...
}
Coordinator
Doneボタンをタップした時の処理を記述します。
ボタンのaddTarget
に指定できるように@objc
修飾子を記載します。
UITextViewRepresentable.swift
struct UITextViewRepresentable: UIViewRepresentable {
...
class Coordinator: NSObject, UITextViewDelegate {
private let parent: UITextViewRepresentable
init(_ parent: UITextViewRepresentable) {
self.parent = parent
}
@objc func onTapDone(_ button: UIButton) {
print(parent.textView.text)
}
}
...
}
キーボードを閉じる処理
UIApplication
のエクステンションを作りました。
この関数をボタンタップ時に実行します。
UIApplication+.swift
import UIKit
extension UIApplication {
func endEditing() {
sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
全体のソースコードはこちらです。
UITextViewRepresentable.swift
struct UITextViewRepresentable: UIViewRepresentable {
@Binding var text: String
private let textView = UITextView()
private let keyboardType: UIKeyboardType
init(
text: Binding<String>,
keyboardType: UIKeyboardType
) {
self._text = text
self.keyboardType = keyboardType
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> UITextView {
textView.delegate = context.coordinator
textView.autocapitalizationType = .none
textView.autocorrectionType = .no
textView.keyboardType = keyboardType
let toolbar = UIToolbar(frame: CGRect(x: .zero, y: .zero, width: textView.frame.size.width, height: 44))
let spacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let doneButton = UIBarButtonItem(
title: "Done",
style: .done,
target: context.coordinator,
action: #selector(context.coordinator.onTapDone(_:))
)
toolbar.setItems([spacer, doneButton], animated: true)
textView.inputAccessoryView = toolbar
return textView
}
func updateUIView(_ uiView: UITextView, context: Context) {
}
class Coordinator: NSObject, UITextViewDelegate {
private let parent: UITextViewRepresentable
init(_ parent: UITextViewRepresentable) {
self.parent = parent
}
@objc func onTapDone(_ button: UIButton) {
print(parent.textView.text)
UIApplication.shared.endEditing()
}
}
}
UITextField
でも同じような方法で要件を実現できると思います。
このビューに渡されるtextは親ビューのテキストとバインドされてるので、親ビューは常に最新の文字列を取得できます。