I'm trying to achieve similar positioning behavior as the bottom text input bar in Apple's Messages app.
I have tried many approaches, searched high and low and there are many similar questions but none have been satisfactory.
To specify:
UIToolbar
at the bottom of the viewThe proposed solutions:
This solution does not meet a special case of the second requirement (the toolbar is to follow the keyboard as the keyboard appears and disappears):
UIScrollViewKeyboardDismissMode
was introduced. It enables an interactive gesture for dismissing the keyboard. As the the user pans past the top edge of the keyboard, the keyboard frame gradually follows. This solution does nothing to accomodate this behavior and just leaves the toolbar stranded at it's animated position.In addition, this solution also fails to fulfil a special case of the third requirement (the toolbar should stay on top of the keyboard when the keyboard is visible):
Another issue with this solution:
Next proposed solution:
UIResponder
's inputAccessoryView
This solution seems to be the way Apple intended to support this kind of behavior, as it solves all the shortcomings of manually animating the toolbar. But this solution completely misses the fourth requirement (when the keyboard is hidden, the toolbar stays ("docked") at the bottom of the view).
It seems the solution is to use UIResponder
's inputAccessoryView
, but somehow making the inputAccessoryView
not move below the view. I'm looking for clean code to accomplish this. There are elaborate, almost noble, attempts elsewhere, but as mentioned, they do not meet the requirements.
In my particular case, I am looking to use UINavigationController
's toolbar which entails additional issues as this is not intended behavior for UINavigationController
. No matter, I'm willing to introduce some hacky fixes to accomplish that.
I was just shown "the" solution by Jason Foreman (@threeve). On your view controller (yes, view controller) add inputAccessoryView:
and return the view you want to dock at the bottom and move with the keyboard. It just works. The view doesn't actually need to be in your view hierarchy it will be inserted by the view controller automatically.
edit: also implement canBecomeFirstResponder and return YES (as noted by Max Seelemann). reloadInputViews can be handy too.
Jonathan Badeen's aforementioned solution worked for me. Here's code from Arik showing how to implement it (this should go in your appropriate view controller):
- (BOOL)canBecomeFirstResponder{
return YES;
}
- (UIView *)inputAccessoryView{
return self.inputAccessoryToolbar;
// where inputAccessoryToolbar is your keyboard accessory view
}
For those looking for Swift version:
Connect your toolbar (in my case 'myToolBar
') on to your view controller. Then override canBecomeFirstResponder
method and override the getter inputAccessoryView
variable. Also don't forget to add the self.myToolBar.removeFromSuperview()
or else xcode will complain.
class ViewController: UIViewController {
@IBOutlet var myToolBar: UIToolbar!
override func canBecomeFirstResponder() -> Bool {
return true
}
override var inputAccessoryView:UIView{
get{
return self.myToolBar
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.myToolBar.removeFromSuperview()
}
}
There's an excellent, easy-to-implement, open-source solution to this from the good folks at Slack: SlackTextViewController.
Here's how to implement a view with a docked toolbar in four steps:
Create a MessageViewController
that inherits from SLKTextViewController
, no need to write any more code than this:
import Foundation
import UIKit
class MessageViewController: SLKTextViewController {
required init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder)
}
}
Props to the team at Slack for extracting such a useful pod.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With