0

I want to accept only decimal values in my textfield.

The following code allows me to enter only numbers and '.' but we can enter more than one '.'

How can i restrict it to just one '.' or how can I restrict the textfield to accept only decimal values in swift 3.1

let aSet = NSCharacterSet(charactersIn:"0123456789.").inverted
let compSepByCharInSet = r_Qty_txt.text?.components(separatedBy: aSet)
let numberFiltered = compSepByCharInSet?.joined(separator: "")

My target device is iPad.

listViewCell.swift Code

import UIKit

class listViewCell: UITableViewCell, UITextFieldDelegate {

var delegate: CellInfoDelegate?

@IBOutlet weak var desc_lbl: UILabel!
@IBOutlet weak var openQty_lbl: UILabel!
@IBOutlet weak var r_Qty_txt: UITextField!
@IBOutlet weak var itemId_lbl: UILabel!

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    let newString: String = (textField.text! as NSString).replacingCharacters(in: range, with: string)
    let expression: String = "^[0-9]*((\\.|,)[0-9]{0,2})?$"
    //var error: Error? = nil
    let regex = try? NSRegularExpression(pattern: expression, options: .caseInsensitive)
    let numberOfMatches: Int = (regex?.numberOfMatches(in: newString, options: [], range: NSRange(location: 0, length: (newString.characters.count ))))!
    return numberOfMatches != 0
}


public func configure(textVal: String?, placeholder: String){
    r_Qty_txt.text = textVal
    r_Qty_txt.placeholder = placeholder

    r_Qty_txt.accessibilityValue = textVal
    r_Qty_txt.accessibilityLabel = placeholder

}

@IBAction func QtyEntered(_ sender: UITextField) {
    print("Value Added \(String(describing: r_Qty_txt.text)) and \(String(describing: openQty_lbl.text))")
    if (r_Qty_txt.text!.isEmpty) {

    }else if(Int(r_Qty_txt.text!)! > Int(openQty_lbl.text!)!){
        print("Not Allowed")
        r_Qty_txt.text = nil
    }
}

override func awakeFromNib() {
    r_Qty_txt.delegate = self
    super.awakeFromNib()
}

override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)

    // Configure the view for the selected state
}
}
Kalpesh
  • 65
  • 2
  • 10

2 Answers2

6

If you want to allow just decimal number with your textField you can simply make it like this way no need to compare anything else.

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    if textField.text != "" || string != "" {
        let res = (textField.text ?? "") + string
        return Double(res) != nil
    }
    return true
}
Nirav D
  • 71,513
  • 12
  • 161
  • 183
  • how do i link this function to my textfield? I have already created an Action for it `@IBAction func receiveQtyEdit(_ sender: UITextField) {` sorry but i'm new to swift. – Kalpesh Jun 01 '17 at 11:37
  • @Kalpesh It is delegate method of `UITextField` means you just need to set delegate of your `textField` you can set it programmatically like `r_Qty_txt.delegate = self` in `viewDidLoad` or you can also set it in interface Builder too – Nirav D Jun 01 '17 at 11:41
  • My textfields are in custom cells. I added UITextFieldDelegate to class `class listViewCell: UITableViewCell, UITextFieldDelegate {` and tried adding `r_QTY.delegate = self` in override func awakeFromNib() { r_Qty_txt.delegate = self super.awakeFromNib() } but it gives me error for `r_QTY.delegate = self` – Kalpesh Jun 01 '17 at 12:09
  • @Kalpesh Then you need to add this method inside your listViewCell after that it will work – Nirav D Jun 01 '17 at 12:10
  • @Kalpesh Is it working now after adding this method in your listViewCell ? – Nirav D Jun 01 '17 at 12:20
  • I have put my method in listViewCell only. it gives me error for `r_Qty_txt.delegate = self` in awakeFromNib and i get `fatal error: unexpectedly found nil while unwrapping an Optional value` in console – Kalpesh Jun 01 '17 at 14:04
  • @Kalpesh Check the outlet connection for `r_Qty_txt` is properly connected or not, if it still not work edit your question with your current code – Nirav D Jun 02 '17 at 05:11
  • @Kalpesh You need to Call `super.awakeFromNib()` first then set delegate of field also have you checked the outlet connection of field is it connected ? – Nirav D Jun 02 '17 at 06:49
  • @Kalpesh Also there is no need to use regx to for valid double number you can go with my solution so remove your code from `shouldChangeCharactersIn` and put my one. – Nirav D Jun 02 '17 at 06:51
  • Yes, my outlet connection is connected, I tried calling `super.awakeFromNib()` and then set deleagte but, Still same i'm getting this error `exc_bad_instruction (code=exc_i386_invop subcode=0x0)` for `r_Qty_txt.delegate = self` – Kalpesh Jun 02 '17 at 07:02
  • @Kalpesh Are you designing cell with XIB or storyboard , try to set delegate in interface builder instead of awakeFromNib – Nirav D Jun 02 '17 at 07:06
  • with xib, i tried setting delegate to listViewCell from Interface builder, i got this error `2017-06-02 13:12:56.526 MobileAutomation[2140:206146] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MobileAutomation.listViewCell receiveQtyEdit:]: unrecognized selector sent to instance 0x7fdb460f1400'` – Kalpesh Jun 02 '17 at 07:43
  • @Kalpesh You may have renamed your `textField` action method that you have set in interface builder remove the action method now you don't need it as of you are using this delegate method. – Nirav D Jun 02 '17 at 08:37
  • @Kalpesh Welcome mate :) – Nirav D Jun 02 '17 at 10:07
1

select keyboard type just like this from atribute inspector for only numbers.

try this delegate for only one dots

and use delegate for only one decimal points(.)

func textField(textField: UITextField,shouldChangeCharactersInRange range: NSRange,replacementString string: String) -> Bool
{
    let countdots = textField.text.componentsSeparatedByString(".").count - 1

    if countdots > 0 && string == "."
    {
        return false
    }
    return true
}
elk_cloner
  • 2,049
  • 1
  • 12
  • 13