UITextField以外からキーボードを表示する方法を紹介します。
以下の画像ではUIViewをカスタマイズしてUITextFieldっぽく見せています。

必須実装
UIViewに準拠した独自のViewを作成し、以下の実装を行う必要があります。
- canBecomeFirstResponder
- canResignFirstResponder
- becomeFirstResponder()
ViewをタップしたタイミングでbecomeFirstResponder()を呼び出すことで、キーボードを表示することができます。
Tips
UIControlを継承することでtapイベントを取得する
UIControlではtouchUpInsideなどのイベントを取得することができるので、init時にaddTargetを呼び出しtap時の処理を登録します。
UITapGestureRecognizerなどの追加は不要です。
inputViewの設定で独自のViewをkeyboard部分に設定する
下のコードでは、UIDatePickerをinputViewに設定することで、キーボード部分で時間を設定できるようにしています。
inputAccessoryViewでkeyboardの上部のViewを設定する
下のコードでは、UIToolbarをinputAccessoryViewに設定し、ボタン押下でキーボードを閉じています。
autoresizingMaskに.flexibleHeightを指定しないと正しく表示できなかったので注意が必要です。
return押下でキーボードを閉じる
UIKeyInputに準拠することでキーボードの入力イベントを取得することができます。
returnを押した時には insertText 関数に textが "\n"
として渡ってくるのでその判定の上で resignFirstResponder()
を呼び出します。
コード全体
import UIKit
final class CustomInputView: UIControl {
override var canBecomeFirstResponder: Bool { !isFirstResponder }
override var canResignFirstResponder: Bool { isFirstResponder }
override var inputAccessoryView: UIView? { toolbar }
override var inputView: UIView? { datePicker }
private lazy var toolbar: UIToolbar = {
let toolbar = UIToolbar()
toolbar.autoresizingMask = .flexibleHeight
toolbar.setItems([
UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelButtonTapped)),
UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil),
UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneButtonTapped))
], animated: false)
return toolbar
}()
let datePicker: UIDatePicker = {
let picker = UIDatePicker()
picker.datePickerMode = .countDownTimer
picker.preferredDatePickerStyle = .wheels
return picker
}()
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
configure()
}
private func configure() {
addTarget(self, action: #selector(itemTapped), for: .touchUpInside)
}
@objc private func itemTapped() {
if isFirstResponder {
resignFirstResponder()
}
else {
becomeFirstResponder()
}
}
@objc private func cancelButtonTapped() {
resignFirstResponder()
}
@objc private func doneButtonTapped() {
resignFirstResponder()
}
}
extension CustomInputView: UIKeyInput {
var hasText: Bool { false }
func insertText(_ text: String) {
if text == "\n" {
resignFirstResponder()
}
}
func deleteBackward() {}
}