I’m trying to implement an input accessory view that works just like Messages app in iOS. I’ve searched almost every SO questions regarding this topic, but couldn’t find the solution that worked for me.
Here is the minimal reproducible code I created, referring to this SO post.
import UIKit
class TestViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
becomeFirstResponder() // seems unnecessary
}
override var inputAccessoryView: UIToolbar {
return self.keyboardAccessory
}
override var canBecomeFirstResponder: Bool {
return true
}
var textView: UITextView = {
let view = UITextView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .yellow
return view
}()
lazy var keyboardAccessory: UIToolbar = {
let inputAccessory = UIToolbar(frame: .init(x: 0, y: 0, width: 0, height: 100))
inputAccessory.addSubview(textView)
NSLayoutConstraint.activate([
textView.centerXAnchor.constraint(equalTo: inputAccessory.centerXAnchor),
textView.centerYAnchor.constraint(equalTo: inputAccessory.centerYAnchor),
textView.widthAnchor.constraint(equalToConstant: 200),
textView.heightAnchor.constraint(equalToConstant: 50)
])
inputAccessory.backgroundColor = .gray
return inputAccessory
}()
}
Every article I’ve seen suggests overriding inputAccessoryView
and canBecomeFirstResponder
, and that’s it. However, the keyboard does not appear until I tap the textView
.
Can anyone let me know what I’m missing?
Edit
As @DonMag pointed out, Messages app in iOS does not show keyboard automatically. Please consider following UI in Facebook instead.
When I press the comment button, it pushes to another view controller while popping up the keyboard. The transition effect doesn’t have to be exactly the same, but I want the keyboard become fully loaded within presented view controller, as if I called becomeFirstResponder()
in viewDidLoad
.
2
Answers
Actually when you override
canBecomeFirstResponder
the keyboard is appear just under the view , thats why you only see the accessory view bottom side of the view . You can basically try this with adding notification to your controller likeWhen you run the project , you gonna see the keyboardWillShow notification is hired.(If you delete
overiride canBecomeFirstResponder
it won’t )And when you print keyboard and view frame , you gonna notice to keyboard’s y position is equal to view’s frame height . That means keyboards want to show us only its accessoryView .
So , you need to hired
textView.becomeFirstResponder()
inkeyboardWillShow
notificationDo not forget to deinit notification when controller deinit
If you want the text view to become active, and the keyboard to show, as soon as the view appears, use:
If you want the text view to be visible at the bottom, and become active / show the keyboard when the textview is tapped, take a look at this answer:
https://stackoverflow.com/a/61508928/6257435
Edit
If you want to push a view controller onto the navigation stack, and have the keyboard showing with a custom input accessory view, containing a text view, and give it the focus…
Add a hidden text field to the controller. In
viewDidLoad
tell that text field to use the custom input accessory view and tell it to become first responder.Then, in
viewDidAppear
tell the text view in the custom input accessory view to become the first responder: