Reputation:
In swift, I am trying to make a text field that will allow a button to be enabled, but only when the text field contains an integer. How can I do this?
Upvotes: 26
Views: 65534
Reputation: 154721
UITextFieldDelegate
by adding UITextFieldDelegate
to the class declaration.IBOutlet
s for your text field and your button.viewDidLoad
set your button's isEnabled
property to false
and set self
as the textField.delegate
.textField:shouldChangeCharactersInRange:replacementString:
method. This method will be called every time your text field is edited. In there, check if the current text field converts to an Int
by calling Int(text)
and enable/disable your button as desired.Here is the code:
class ViewController : UIViewController, UITextFieldDelegate {
@IBOutlet weak var textField: UITextField!
@IBOutlet weak var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
button.isEnabled = false
textField.delegate = self
textField.keyboardType = .numberPad
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
// Find out what the text field will be after adding the current edit
let text = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
if Int(text) != nil {
// Text field converted to an Int
button.isEnabled = true
} else {
// Text field is not an Int
button.isEnabled = false
}
// Return true so the text field will be changed
return true
}
}
Upvotes: 22
Reputation: 1829
IN SWIFT 4
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField == mobileTF{
let allowingChars = "0123456789"
let numberOnly = NSCharacterSet.init(charactersIn: allowingChars).inverted
let validString = string.rangeOfCharacter(from: numberOnly) == nil
return validString
}
return true
}
Upvotes: 1
Reputation: 557
As for accept backspace and other control characters I've used following method:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if string.isEmpty { // This is for accept control characters
return true
}
let numericRegEx = "[0-9]"
let predicate = NSPredicate(format:"SELF MATCHES %@", numericRegEx)
let newText = (textFieldCount.text as! NSString).replacingCharacters(in: range, with: string)
return predicate.evaluate(with: string)
}
If you want it to accept floating points also, just change RegEx to
let numericRegEx = "[.0-9]"
If limit text size to 10, change last row as following:
return predicate.evaluate(with: string) && newText.count < 10
Upvotes: 0
Reputation: 2415
1st you have to inherit the UITextViewDelegate class with you own class
class ViewController: UIViewController, UITextViewDelegate {
2nd add an IBOutlet
@IBOutlet weak var firstName: UITextField!
3rd you have to assure this object is using
override func viewDidLoad() {
super.viewDidLoad()
firstName.delegate = self
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if textField == firstName {
let allowedCharacters = "1234567890"
let allowedCharacterSet = CharacterSet(charactersIn: allowedCharacters)
let typedCharacterSet = CharacterSet(charactersIn: string)
let alphabet = allowedCharacterSet.isSuperset(of: typedCharacterSet)
return alphabet
}
}
Upvotes: 2
Reputation: 438467
Two things:
Specify the keyboard type to only show the numeric keypad. So, set the keyboardType
to .numberPad
. This, however is not enough to stop the user from entering invalid characters in the text field. For example, the user is still able to paste text or switch keyboards when using an iPad.
Specify the text field's delegate and implement shouldChangeCharactersInRange
that will not accept any characters other than the digits 0
though 9
:
class ViewController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// you can set the following two properties for the text field in Interface Builder, if you'd prefer
textField.delegate = self
textField.keyboardType = .numberPad
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let invalidCharacters = CharacterSet(charactersIn: "0123456789").inverted
return string.rangeOfCharacter(from: invalidCharacters) == nil
}
// or, alternatively:
//
// func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
// return string.range(of: "^\\d*$", options: .regularExpression) != nil
// }
}
For Swift 2 rendition, see previous revision of this answer.
Upvotes: 59
Reputation: 12383
Swift 4: How about a simple guard
and typecasting to Int
as below
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let _ = Int(string) else {
button.isEnabled = false
return true
}
button.isEnabled = true
return true
}
Upvotes: 4
Reputation: 3983
Here's a reusable method for Cocoa, swift 4.1
1- Create a file with the class NSTextFieldFormated below
2- In the 'Identity inspector' change the 'CustomClass class' of the field to be formatted to NSTextFieldFormated
3- In the 'Attributes inspector' define the 'int Min Value', 'int Max Value' and 'int Length' of the field to be formatted
4- Drag and drop an 'Object' (NSObject) from the 'Object library' to the 'View Controller Scene' in the outline interface builder objects listing (left of the interface drawing area)
5- In the 'Identity inspector' set the 'CustomClass class' to NSTextFieldFormated
6- Select the field to be formatted and in the Connections inspector set the field delegate to the new 'Text Field Formatted' object in 'View Controller Scene'.
Then the NSTextField is now formatted.
class NSTextFieldFormated: NSTextField, NSControlTextEditingDelegate {
private struct Digit {
var minValue: Int? // minimum
var maxValue: Int? // maximum
var digitAmt: Int? // minimumIntegerDigits
}
private var digit = Digit()
//-Integer
@IBInspectable var intMinValue: Int {
get {
guard let minVal = digit.minValue else { return Int.min }
return minVal
}
set { digit.minValue = newValue ; setFormatter() }
}
@IBInspectable var intMaxValue: Int {
get {
guard let maxVal = digit.maxValue else { return Int.max }
return maxVal
}
set { digit.maxValue = newValue ; setFormatter() }
}
@IBInspectable var intLenght: Int {
get {
guard let length = digit.digitAmt else { return -1 }
return length
}
set { digit.digitAmt = newValue ; setFormatter() }
}
private func setFormatter() {
let lformatter = IntegerFormatter()
lformatter.minimum = intMinValue as NSNumber
lformatter.maximum = intMaxValue as NSNumber
if intLenght != -1 {
lformatter.minimumIntegerDigits = intLenght
}
self.formatter = lformatter
}
class IntegerFormatter: NumberFormatter {
override func isPartialStringValid(_ partialString: String,
newEditingString newString: AutoreleasingUnsafeMutablePointer<NSString?>?,
errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {
if partialString.rangeOfCharacter(from: CharacterSet.decimalDigits.inverted) != nil {
NSSound.beep()
return false
}
return Int(partialString) != nil
}
}
override func controlTextDidChange(_ notification: Notification) {
if let textField = notification.object as? NSTextFieldFormated {
if let val = Int(textField.stringValue) {
//print(">4")
if val > textField.intMaxValue {
textField.stringValue = String(textField.intMaxValue)
}
}
}
}
}
Upvotes: 0
Reputation: 1870
You can use NSScanner to do that here is the which might be useful trying using this and let me know if there are any issues
if( [[NSScanner scannerWithString:@"-123.4e5"] scanFloat:NULL] )
NSLog( @"\"-123.4e5\" is numeric" );
else
NSLog( @"\"-123.4e5\" is not numeric" );
if( [[NSScanner scannerWithString:@"Not a number"] scanFloat:NULL] )
NSLog( @"\"Not a number\" is numeric" );
else
NSLog( @"\"Not a number\" is not numeric" );
go through the link http://rosettacode.org/wiki/Determine_if_a_string_is_numeric#Objective-C. Try it in swift the class and method names are same.
Upvotes: 0
Reputation: 670
Each text field has a keyboardType
. You could set this to UIKeyboardType.NumbersAndPunctuation
to only show numbers and still have the return key present (defensive UI). You could then use NSScanner
's scanInt()
to check if textField.text is a valid integer.
Upvotes: 1