Add UIToolBar to all keyboards (swift)
Asked Answered
D

5

19

I'm trying to add a custom UIToolBar to all of my keyboards with as little repetition. The way I'm currently doing it requires me to add the code to all my viewDidLoads and assign every textfield's delegate to the viewController I'm using. I have tried creating my own UIToolBar subclass but I find that I can't really do that when the target for my "Done" and "cancel" buttons are the self view. Does anyone have any suggestions for creating an easily reusable toolbar? Thanks in advance.

override func viewDidLoad() {
    super.viewDidLoad()

    var toolBar = UIToolbar()
    toolBar.barStyle = UIBarStyle.Default
    toolBar.translucent = true
    toolBar.tintColor = UIColor(red: 76/255, green: 217/255, blue: 100/255, alpha: 1)
    var doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.Done, target: self, action: "donePressed")
    var cancelButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.Plain, target: self, action: "cancelPressed")
    var spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil)
    toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
    toolBar.userInteractionEnabled = true
    toolBar.sizeToFit()

    stateField.inputAccessoryView = toolBar
    stateField.delegate = self
Disannul answered 22/6, 2015 at 15:8 Comment(1)
Subclass UITextField? Maybe it also works with extensions.Mimetic
D
55

Thanks to Glorfindel's suggestion and ncerezo's sample code I solved my problem using extensions.

extension UIViewController: UITextFieldDelegate{
    func addToolBar(textField: UITextField){
        var toolBar = UIToolbar()
        toolBar.barStyle = UIBarStyle.Default
        toolBar.translucent = true
        toolBar.tintColor = UIColor(red: 76/255, green: 217/255, blue: 100/255, alpha: 1)
        var doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.Done, target: self, action: "donePressed")
        var cancelButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.Plain, target: self, action: "cancelPressed")
        var spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil)
        toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
        toolBar.userInteractionEnabled = true
        toolBar.sizeToFit()

        textField.delegate = self
        textField.inputAccessoryView = toolBar
    }
    func donePressed(){
        view.endEditing(true)
    }
    func cancelPressed(){
        view.endEditing(true) // or do something
    }
}

Though I still need to call the code below on all of my textfields. I feel like there may be a better way without having to call the function on every textField, but for now this is definitely more reusable.

override func viewDidLoad() {
    super.viewDidLoad()
    addToolBar(addressField)
}
Disannul answered 23/6, 2015 at 18:27 Comment(1)
Add the following line @IBOutlet var textFields: [UITextField]! to your ViewController. Then go to storyboard and control drag all your textfields into it. Then do : for textField in textFields { addToolBar(textField) } - Much cleaner than multiple lines of code.Hymeneal
T
16

equivalent of vivian version in swift 3:

extension UIViewController: UITextFieldDelegate {
    func addToolBar(textField: UITextField) {
        let toolBar = UIToolbar()
        toolBar.barStyle = .default
        toolBar.isTranslucent = true
        toolBar.tintColor = UIColor(red: 76 / 255, green: 217 / 255, blue: 100 / 255, alpha: 1)
        let doneButton = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(donePressed))
        let cancelButton = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(cancelPressed))
        let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)


        toolBar.isUserInteractionEnabled = true
        toolBar.sizeToFit()

        textField.delegate = self
        textField.inputAccessoryView = toolBar
    }

    func donePressed() {
        view.endEditing(true)
    }

    func cancelPressed() {
        view.endEditing(true) // or do something
    }
}
Twum answered 24/11, 2016 at 16:25 Comment(1)
What to do if I need to set images on Done and Cancel buttons?Sporades
C
3

For swift 4 you can use this:-

extension UIViewController : UITextFieldDelegate {
    func addToolBar(textField: UITextField){
        var toolBar = UIToolbar()
        toolBar.barStyle = UIBarStyle.default
        toolBar.isTranslucent = true
        toolBar.tintColor = UIColor(red: 76/255, green: 217/255, blue: 100/255, alpha: 1)
        var doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.done, target: self, action: "donePressed")
        var cancelButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.plain, target: self, action: "cancelPressed")
        var spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
        toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
        toolBar.isUserInteractionEnabled = true
        toolBar.sizeToFit()

        textField.delegate = self
        textField.inputAccessoryView = toolBar
    }
    func donePressed(){
        view.endEditing(true)
    }
    func cancelPressed(){
        view.endEditing(true) // or do something
    }
}

Use

override func viewDidLoad() {
      super.viewDidLoad()
      addToolBar(addressField)
 }
Caundra answered 16/8, 2018 at 6:52 Comment(0)
C
0

I have an utility that I've been using some time (ported to Swift from Objective-C) that does this and a little more, you might find it useful:

https://github.com/ncerezo/SwiftKeyboardAccessory

It creates a toolbar with at least a "Done" button to dismiss the keyboard, and optionally Next and Previous buttons. It also takes care of dismissing the keyboard when you tap outside the text field, and of resizing and scrolling the view when the keyboard appears or disappears. It's designed to work with UITableVIew and also with UIScrollView.

Candent answered 22/6, 2015 at 19:11 Comment(0)
T
0

You can make a UIToolbar subclass work by taking advantage of the responder chain. No need to change your view controllers. In Swift 3:

class KeyboardAccessoryToolbar: UIToolbar {
    convenience init() {
        self.init(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
        self.barStyle = .default
        self.isTranslucent = true
        self.tintColor = UIColor(red: 76 / 255, green: 217 / 255, blue: 100 / 255, alpha: 1)

        let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.done))
        let cancelButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(self.cancel))
        let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        self.items = [cancelButton, spaceButton, doneButton]

        self.isUserInteractionEnabled = true
        self.sizeToFit()
    }

    func done() {
        // Tell the current first responder (the current text input) to resign.
        UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
    }

    func cancel() {
        // Call "cancel" method on first object in the responder chain that implements it.
        UIApplication.shared.sendAction(#selector(cancel), to: nil, from: nil, for: nil)
    }
}

Then add the following to your applicationDidFinishLaunching to apply this to all your keyboards:

    let accessoryView = KeyboardAccessoryToolbar()
    UITextField.appearance().inputAccessoryView = accessoryView
    UITextView.appearance().inputAccessoryView = accessoryView
Trichinopoly answered 11/1, 2018 at 23:30 Comment(2)
Two issues I see with this: 1. The keyboard dismissal does not seem to be animated. 2. Is there a way in a view controller to receive a message when the done button is pressed and to determine which textfield triggered the done button?Gynophore
@Gynophore I haven't seen any problems with animation using this method, testing on iOS 11.4. For 2., you can set your view controller as the UITextFieldDelegate for your text field and implement the textFieldDidEndEditing method.Trichinopoly

© 2022 - 2024 — McMap. All rights reserved.