user4241521
user4241521

Reputation:

How can I declare that a text field can only contain an integer?

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

Answers (9)

vacawama
vacawama

Reputation: 154721

  1. Make your view controller a UITextFieldDelegate by adding UITextFieldDelegate to the class declaration.
  2. Add IBOutlets for your text field and your button.
  3. In viewDidLoad set your button's isEnabled property to false and set self as the textField.delegate.
  4. Implement 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

Sai kumar Reddy
Sai kumar Reddy

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

Murat Uygar
Murat Uygar

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

Akbar Khan
Akbar Khan

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

Rob
Rob

Reputation: 438467

Two things:

  1. 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.

  2. 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

Naishta
Naishta

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

Luc-Olivier
Luc-Olivier

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

yashwanth77
yashwanth77

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

mumush
mumush

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

Related Questions