Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making UIToolbar with TextField move up with keyboard

Tags:

xcode

ios

swift

I have an UIToolbar with a TextField and a Button as UIBarButtonItem. I'm trying to use this toolbar as an inputAccessory for the keyboard when the user taps the TextField inside the toolbar.

enter image description here

I found this question that tries to solve the same problem. Unfortunately, the solution was not effective.

What i'm trying is:

class ChatViewController: UIViewController, CLLocationManagerDelegate, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var chatTableView: UITableView!
    @IBOutlet weak var chatToolbar: UIToolbar!

    @IBOutlet weak var textFieldBarButtonItem: UIBarButtonItem!

    override func viewDidAppear(animated: Bool) {
        super.viewDidLoad()
        self.chatTableView.delegate = self
        self.chatTableView.dataSource = self
        self.chatToolbar.removeFromSuperview()

    }

    override var inputAccessoryView: UIView{
        get{
            return self.chatToolbar
        }
    }

    override func canBecomeFirstResponder() -> Bool {
        return true
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{

        let cell = UITableViewCell()
        return cell
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        return 0
    }

}

And what i'm getting back is:

*** Terminating app due to uncaught exception 'UIViewControllerHierarchyInconsistency', reason: 
'child view controller:<UICompatibilityInputViewController: 0x13ff34e00> should have parent view controller:
<App.ChatViewController: 0x13ff21cc0> but requested parent is:<UIInputWindowController: 0x1400b4600>'

Any ideas?

like image 583
adolfosrs Avatar asked Oct 16 '25 06:10

adolfosrs


1 Answers

First things first:

  1. You should create constraints to your Toolbar in Storyboard (left, bottom, right).
  2. Create an outlet to your bottom constraint in your view controller (drag from storyboard). Save initial constraint value (to recover when keyboard disappears)
  3. Create an observer to know when your keyboard appears and disappears (3.1 and create a tap gesture to hide your keyboard)
  4. When keyboard 4.1 appears and 4.2 disappears, you will only change bottom constraint value (keyboard size). You can animate the toolbar too.

Something like:

class ChatViewController: UIViewController, CLLocationManagerDelegate, UITableViewDelegate, UITableViewDataSource {

    @IBOutlet weak var chatTableView: UITableView!
    @IBOutlet weak var chatToolbar: UIToolbar!

    @IBOutlet weak var textFieldBarButtonItem: UIBarButtonItem!

    //2
    @IBOutlet weak var toolbarBottomConstraint: NSLayoutConstraint!
    var toolbarBottomConstraintInitialValue: CGFloat?

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        self.chatTableView.delegate = self
        self.chatTableView.dataSource = self
        self.chatToolbar.removeFromSuperview()

        //2
        self.toolbarBottomConstraintInitialValue = toolbarBottomConstraint.constant
        //3
        enableKeyboardHideOnTap()

    }

    // 3
    // Add a gesture on the view controller to close keyboard when tapped
    private func enableKeyboardHideOnTap(){

        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil) // See 4.1
        NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil) //See 4.2            

        // 3.1
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "hideKeyboard")

        self.view.addGestureRecognizer(tap)
    }

    //3.1
    func hideKeyboard() {
        self.view.endEditing(true)
    }

    //4.1
    func keyboardWillShow(notification: NSNotification) {

        let info = notification.userInfo!

        let keyboardFrame: CGRect = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()

        let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double        

        UIView.animateWithDuration(duration) { () -> Void in

            self.toolbarBottomConstraint.constant = keyboardFrame.size.height + 5

            self.view.layoutIfNeeded()

        }

    }

    //4.2
    func keyboardWillHide(notification: NSNotification) {

        let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double

        UIView.animateWithDuration(duration) { () -> Void in

            self.toolbarBottomConstraint.constant = self.toolbarBottomConstraintInitialValue!
            self.view.layoutIfNeeded()

        }

    }

    override var inputAccessoryView: UIView{
        get{
            return self.chatToolbar
        }
    }

    override func canBecomeFirstResponder() -> Bool {
        return true
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{

        let cell = UITableViewCell()
        return cell
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        return 0
    }

}

Hope it helps!

like image 195
Jonathan Andrade Avatar answered Oct 17 '25 21:10

Jonathan Andrade



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!