画像のようにキーボードの上にツールバーがのった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は親ビューのテキストとバインドされてるので、親ビューは常に最新の文字列を取得できます。