Amit Kalra
Amit Kalra

Reputation: 4113

How to add a return key on a decimal pad in Swift?

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 this

Something like that

Upvotes: 44

Views: 31770

Answers (5)

Mike Moening
Mike Moening

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

ShadeToD
ShadeToD

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

oli
oli

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.

enter image description here

//
//  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

Karen Gonzalez
Karen Gonzalez

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))
  }
}

This is the result

Upvotes: 29

maquannene
maquannene

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()
    }
}

enter image description here

Upvotes: 2

Related Questions