Reputation: 4113
I have the decimal pad setup in my app, but how do I dismiss this keyboard? How do I get a done or a return key? I've tried UIReturnKeyType.Done
but that didn't show anything.
Something like that
Upvotes: 44
Views: 31770
Reputation: 473
Here's a solution for the latest SwiftUI & XCode 13.x The KEY is to make sure toobar has a NavigationView around it. Otherwise it won't work.
var body: some View {
//In my implementation the NavigationView is down inside a few nested VStack or HStack containers.
NavigationView {
TextField("enter stuff", text: $stuff)
.keyboardType(.numberPad)
.frame(height: 30, alignment: .leading)
.toolbar() {
ToolbarItemGroup(placement: .keyboard) {
Button(action: { fieldInFocus = nil}, label: {Text("Cancel").bold()})
Button(action: { fieldInFocus = nil; DoSomething()}, label: {Text("Return").bold()})
}
}
.navigationBarHidden(true)
}
}
Upvotes: 3
Reputation: 489
Updates @olito answer for Swift 4.2 For swift 4 selector must be objc method, so we have to add @objc to our functions inside extension
extension UITextField {
func addDoneCancelToolbar(onDone: (target: Any, action: Selector)? = nil, onCancel: (target: Any, action: Selector)? = nil) {
let onCancel = onCancel ?? (target: self, action: #selector(cancelButtonTapped))
let onDone = onDone ?? (target: self, action: #selector(doneButtonTapped))
let toolbar: UIToolbar = UIToolbar()
toolbar.barStyle = .default
toolbar.items = [
UIBarButtonItem(title: "Cancel", style: .plain, target: onCancel.target, action: onCancel.action),
UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil),
UIBarButtonItem(title: "Done", style: .done, target: onDone.target, action: onDone.action)
]
toolbar.sizeToFit()
self.inputAccessoryView = toolbar
}
// Default actions:
@objc func doneButtonTapped() { self.resignFirstResponder() }
@objc func cancelButtonTapped() { self.resignFirstResponder() }}
(Make sure to connect IBOutlet)
@IBOutlet weak var vehicleModelTF: UITextField!
In viewDidLoad we can add toolbar to textfield.
myTextField.addDoneCancelToolbar(onDone: (target: self, action: #selector(self.tapDone)), onCancel: (target: self, action: #selector(self.tapCancel)))
Now we have to add 2 objc methods.
@objc func tapDone() {
print("tapped Done")
}
@objc func tapCancel() {
print("tapped cancel")
}
Upvotes: 9
Reputation: 1969
Here is a Swift 3 solution using an extension. Ideal if you have several numeric UITextField
objects in your app as it gives the flexibility to decide, for each UITextField
, whether to perform a custom action when Done or Cancel is tapped.
//
// UITextField+DoneCancelToolbar.swift
//
import UIKit
extension UITextField {
func addDoneCancelToolbar(onDone: (target: Any, action: Selector)? = nil, onCancel: (target: Any, action: Selector)? = nil) {
let onCancel = onCancel ?? (target: self, action: #selector(cancelButtonTapped))
let onDone = onDone ?? (target: self, action: #selector(doneButtonTapped))
let toolbar: UIToolbar = UIToolbar()
toolbar.barStyle = .default
toolbar.items = [
UIBarButtonItem(title: "Cancel", style: .plain, target: onCancel.target, action: onCancel.action),
UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil),
UIBarButtonItem(title: "Done", style: .done, target: onDone.target, action: onDone.action)
]
toolbar.sizeToFit()
self.inputAccessoryView = toolbar
}
// Default actions:
func doneButtonTapped() { self.resignFirstResponder() }
func cancelButtonTapped() { self.resignFirstResponder() }
}
Example of usage using the default actions:
//
// MyViewController.swift
//
@IBOutlet weak var myNumericTextField: UITextField! {
didSet { myNumericTextField?.addDoneCancelToolbar() }
}
Example of usage using a custom Done action:
//
// MyViewController.swift
//
@IBOutlet weak var myNumericTextField: UITextField! {
didSet {
myNumericTextField?.addDoneCancelToolbar(onDone: (target: self, action: #selector(doneButtonTappedForMyNumericTextField)))
}
}
func doneButtonTappedForMyNumericTextField() {
print("Done");
myNumericTextField.resignFirstResponder()
}
Upvotes: 65
Reputation: 674
This solution worked for me =)
Source: https://gist.github.com/jplazcano87/8b5d3bc89c3578e45c3e
I made an extension for UITextField and now I can have a "Done Bar" on all the keyboards I want.
extension UITextField{
func addDoneButtonToKeyboard(myAction:Selector?){
let doneToolbar: UIToolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: 300, height: 40))
doneToolbar.barStyle = UIBarStyle.default
let flexSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
let done: UIBarButtonItem = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.done, target: self, action: myAction)
var items = [UIBarButtonItem]()
items.append(flexSpace)
items.append(done)
doneToolbar.items = items
doneToolbar.sizeToFit()
self.inputAccessoryView = doneToolbar
}
}
MyViewController
class myViewController:UIViewController,UITextFieldDelegate{
//MARK: - Outlets
@IBOutlet weak var myTextField: UITextField!
//MARK: - Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
myTextField.delegate = self
//You can specify your own selector to be send in "myAction"
myTextField.addDoneButtonToKeyboard(myAction: #selector(self.myTextField.resignFirstResponder))
}
}
Upvotes: 29
Reputation: 2317
class ViewController: UIViewController {
let textField = UITextField(frame: CGRect(x: 0, y: 20, width: 200, height: 60))
override func viewDidLoad() {
super.viewDidLoad()
textField.borderStyle = .Line
textField.inputAccessoryView = accessoryView()
textField.inputAccessoryView?.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: 44)
view.addSubview(textField)
}
func accessoryView() -> UIView {
let view = UIView()
view.backgroundColor = UIColor.redColor()
let doneButton = UIButton()
doneButton.frame = CGRect(x: self.view.frame.width - 80, y: 7, width: 60, height: 30)
doneButton.backgroundColor = UIColor.greenColor()
doneButton.setTitle("done", forState: .Normal)
doneButton.addTarget(self, action: #selector(ViewController.doneAction), forControlEvents: .TouchUpInside)
view.addSubview(doneButton)
return view
}
@objc func doneAction() {
textField.resignFirstResponder()
}
}
Upvotes: 2