Reputation: 1339
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
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
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