LoginSignup
1
1

More than 1 year has passed since last update.

SwiftUIでUITextViewの上にtoolbarをのせる

Last updated at Posted at 2023-02-24

画像のようにキーボードの上にツールバーがのったUIを作成します。
要件は以下のとおりです。

  1. キーボードの上にツールバーが表示する
  2. ツールバーのボタンをタップするとキーボードが閉じる
  3. タップ時にログに入力した文字列を表示する

UITextViewUIViewRepresentableに準拠させる実装を行います。

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は親ビューのテキストとバインドされてるので、親ビューは常に最新の文字列を取得できます。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1