Jess Murray
Jess Murray

Reputation: 1339

shouldChangeCharactersInRange which accepts a single '.'

I have a text field which only accepts numerical values. I was wondering how I can include the ability to type a single '.' to represent a decimal point.

I have the following code:

class ViewController: UIViewController, UITextFieldDelegate {

    var formatter: NSNumberFormatter!

    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    return string == "" || Double(string) != nil
    }

    override func viewDidLoad() {
        amountTextField.delegate = self
        // Initialize the formatter; minimum value is set to zero; style is Decimal.
        formatter = NSNumberFormatter()
        formatter.numberStyle = NSNumberFormatterStyle.DecimalStyle
        formatter.minimum = 0
    }
}

Upvotes: 0

Views: 115

Answers (2)

Alexander Doloz
Alexander Doloz

Reputation: 4198

You can use target-action with .EditingChanged event instead of this delegate method, because it's inconvenient (doesn't give you the value of text after change) and not always works (autocorrection, for example).

In handler for .EditingChanged you can handle entered text using regexp. With this approach you will have to keep old text value.

Example code:

let decimalRegex = try! NSRegularExpression(pattern: "^[0-9]+(\\.[0-9]+)?$", options: [])

func isValidText(text: String) -> Bool {
    return text == "" || decimalRegex.numberOfMatchesInString(text, options: [], range: NSMakeRange(0, text.utf16.count)) != 0
}

textField.addTarget(self, action: #selector(self.textFieldTextChanged(_:)), forControlEvents: .EditingChanged)
var oldText = ""

func textFieldTextChanged(textField: UITextField) {
    if isValidText(textField.text!) {
        oldText = textField.text!
    } else {
        textField.text = oldText
    }
}

Upvotes: 0

pableiros
pableiros

Reputation: 16052

You have to use this text field delegate method:

 func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { // return NO to not change text

        let newString = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)

        if newString.characters.count > 0 {

            let scanner: NSScanner = NSScanner(string:newString)
            let isNumeric = scanner.scanDecimal(nil) && scanner.atEnd

            return isNumeric

        } else {

            return true
        }
    }

Upvotes: 1

Related Questions