After much research and trials, this seems to be a working solution for trying to use UIToolbar
with a text input's inputAccessoryView
. (Most of the existing solutions are for using fixed accessory view instead of assigning it to a text view (and hiding it when the keyboard is closed).)
The code is inspired by https://stackoverflow.com/a/46510833/2603230. Basically, we first create a custom view that has a toolbar subview:
class CustomInputAccessoryWithToolbarView: UIView {
public var toolbar: UIToolbar!
override init(frame: CGRect) {
super.init(frame: frame)
// https://stackoverflow.com/a/58524360/2603230
toolbar = UIToolbar(frame: frame)
// Below is adopted from https://stackoverflow.com/a/46510833/2603230
self.addSubview(toolbar)
self.autoresizingMask = .flexibleHeight
toolbar.translatesAutoresizingMaskIntoConstraints = false
toolbar.leadingAnchor.constraint(
equalTo: self.leadingAnchor,
constant: 0
).isActive = true
toolbar.trailingAnchor.constraint(
equalTo: self.trailingAnchor,
constant: 0
).isActive = true
toolbar.topAnchor.constraint(
equalTo: self.topAnchor,
constant: 0
).isActive = true
// This is the important part:
if #available(iOS 11.0, *) {
toolbar.bottomAnchor.constraint(
equalTo: self.safeAreaLayoutGuide.bottomAnchor,
constant: 0
).isActive = true
} else {
toolbar.bottomAnchor.constraint(
equalTo: self.layoutMarginsGuide.bottomAnchor,
constant: 0
).isActive = true
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// https://stackoverflow.com/a/46510833/2603230
// This is needed so that the inputAccesoryView is properly sized from the auto layout constraints.
// Actual value is not important.
override var intrinsicContentSize: CGSize {
return CGSize.zero
}
}
Then you can set it as an inputAccessoryView
for a text input normally: (You should specify the frame size to avoid the warnings seen in UIToolbar with UIBarButtonItem LayoutConstraint issue)
let myAccessoryView = CustomInputAccessoryWithToolbarView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 44))
textView.inputAccessoryView = myAccessoryView
When you want to interact with the toolbar (e.g., set items on the toolbar), you can simply refer to the toolbar
variable:
myAccessoryView.toolbar.setItems(myToolbarItems, animated: true)
Demo: (with hardware keyboard / Command+K in simulator)
Before:

After:
