Comment restreindre UITextField pour ne prendre que des nombres dans Swift?

Je souhaite que l'user entre uniquement des valeurs numériques dans un UITextField . Sur iPhone, nous pouvons afficher le keyboard numérique, mais sur iPad, l'user peut passer à n'importe quel keyboard.

Est-il possible de limiter l'user pour entrer uniquement des valeurs numériques dans un UITextField ?

Voici mes 2 cents. (Testé sur Swift 2 seulement)

 func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementSsortingng ssortingng: Ssortingng) -> Bool { let aSet = NSCharacterSet(charactersInSsortingng:"0123456789").invertedSet let compSepByCharInSet = ssortingng.componentsSeparatedByCharactersInSet(aSet) let numberFiltered = compSepByCharInSet.joinWithSeparator("") return ssortingng == numberFiltered } 

C'est juste un peu plus ssortingct. Pas de point décimal non plus.

J'espère que cela aide 🙂

PS: Je suppose que vous avez pris soin du délégué de toute façon.

Mise à jour: Swift 3.0 :

 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementSsortingng ssortingng: Ssortingng) -> Bool { let aSet = NSCharacterSet(charactersIn:"0123456789").inverted let compSepByCharInSet = ssortingng.components(separatedBy: aSet) let numberFiltered = compSepByCharInSet.joined(separator: "") return ssortingng == numberFiltered } 

Solution pour swift 3.0 et supérieur

 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementSsortingng ssortingng: Ssortingng) -> Bool { let allowedCharacters = CharacterSet.decimalDigits let characterSet = CharacterSet(charactersIn: ssortingng) return allowedCharacters.isSuperset(of: characterSet) } 

Swift 2.0

Pour seulement permettre des nombres et un "." décimal dans uitextfield.

 func textField(textField: UITextField,shouldChangeCharactersInRange range: NSRange,replacementSsortingng ssortingng: Ssortingng) -> Bool { let newCharacters = NSCharacterSet(charactersInSsortingng: ssortingng) let boolIsNumber = NSCharacterSet.decimalDigitCharacterSet().isSupersetOfSet(newCharacters) if boolIsNumber == true { return true } else { if ssortingng == "." { let countdots = textField.text!.componentsSeparatedBySsortingng(".").count - 1 if countdots == 0 { return true } else { if countdots > 0 && ssortingng == "." { return false } else { return true } } } else { return false } } } 

Accepter les valeurs décimales dans les champs de text avec un seul point (.) Dans Swift 3

 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementSsortingng ssortingng: Ssortingng) -> Bool { let inverseSet = NSCharacterSet(charactersIn:"0123456789").inverted let components = ssortingng.components(separatedBy: inverseSet) let filtered = components.joined(separator: "") if filtered == ssortingng { return true } else { if ssortingng == "." { let countdots = textField.text!.components(separatedBy:".").count - 1 if countdots == 0 { return true }else{ if countdots > 0 && ssortingng == "." { return false } else { return true } } }else{ return false } } } 
 func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementSsortingng ssortingng: Ssortingng) -> Bool { // return true if the replacementSsortingng only contains numeric characters let digits = NSCharacterSet.decimalDigitCharacterSet() for c in ssortingng { if !digits.characterIsMember(c) { return false } } return true } 

Cette solution fonctionnera même si l'user change de keyboard ou tente de coller une string non numérique dans le champ de text.

Assurez-vous de définir la propriété delegate du champ de text approprié.

Je l'avais fait en travaillant à travers le livre Big Nerd Ranch, ma solution est la suivante:

 func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementSsortingng ssortingng: Ssortingng) -> Bool { let newCharacters = NSCharacterSet(charactersInSsortingng: ssortingng) return NSCharacterSet.decimalDigitCharacterSet().isSupersetOfSet(newCharacters) } 

ceci permet seulement les nombres 0-9, pour permettre le "." ainsi est plus compliqué que vous ne pouvez en autoriser qu'un "."

 func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementSsortingng ssortingng: Ssortingng) -> Bool { if let numRange = ssortingng.rangeOfCharacterFromSet(NSCharacterSet.letterCharacterSet()) { return false } else { return true } } 

Testé dans swift 3.0

 func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementSsortingng ssortingng: Ssortingng) -> Bool { let numberOnly = NSCharacterSet.init(charactersIn: "0123456789") let ssortingngFromTextField = NSCharacterSet.init(charactersIn: ssortingng) let strValid = numberOnly.isSuperset(of: ssortingngFromTextField as CharacterSet) return strValid } 

Je pense que vous pouvez forcer le changement du type de keyboard en implémentant le protocole UITextInputTraits, optionnel var keyboardType

 //class ViewController: UIViewController, UITextInputTraits { @IBOutlet weak var textFieldKeyboardType: UITextField!{ didSet{ textFieldKeyboardType.keyboardType = UIKeyboardType.NumberPad } } var keyboardType: UIKeyboardType { get{ return textFieldKeyboardType.keyboardType } set{ if newValue != UIKeyboardType.NumberPad{ self.keyboardType = UIKeyboardType.NumberPad } } } 

Bien que la plupart de ces solutions fonctionnent, sachez que dans certaines localizations, les décimales sont séparées par un "," et non un "."

La façon plus propre de faire cela serait

 func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementSsortingng ssortingng: Ssortingng) -> Bool { let decimalCharacter = NSNumberFormatter().decimalSeparator let characterSet = NSMutableCharacterSet.decimalDigitCharacterSet() characterSet.addCharactersInSsortingng(decimalCharacter) return replacementSsortingng.rangeOfCharacterFromSet(characterSet.invertedSet) == nil } 

Comme s'il n'y avait pas assez de réponses, voici le mien. Je pense que tous les exemples autorisés pour les séparateurs décimaux sont erronés dans la localization, les espaces de return ou le copyr / coller.

 func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementSsortingng ssortingng: Ssortingng) -> Bool { if ssortingng.isEmpty {return true} //allow for backspace let decimalSeparator = NSNumberFormatter().decimalSeparator ?? "." let validChars = NSMutableCharacterSet(charactersInSsortingng: decimalSeparator) validChars.formUnionWithCharacterSet(NSCharacterSet.decimalDigitCharacterSet()) if validChars.isSupersetOfSet(NSCharacterSet(charactersInSsortingng: ssortingng)){ switch ssortingng.componentsSeparatedBySsortingng(decimalSeparator).count-1 { case 0: //no decimals return true case 1: //if adding decimal, only allow if no existing decimal if let existingText = textField.text{ return existingText.componentsSeparatedBySsortingng(decimalSeparator).count <= 1 } else {return true} default: //invalid decimals return false } } return false } 

Pour autoriser uniquement les nombres et un seul opérateur décimal, vous pouvez utiliser cette solution:

 func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementSsortingng ssortingng: Ssortingng) -> Bool { let isNumber = NSCharacterSet.decimalDigitCharacterSet().isSupersetOfSet(NSCharacterSet(charactersInSsortingng: ssortingng)) return isNumber || (ssortingng == NSNumberFormatter().decimalSeparator && textField.text?.containsSsortingng(ssortingng) == false) } 

Ce qui suit est le code que j'ai utilisé dans Swift 3.0 adapté du code de Mr H. Les différences sont parce que:

a) La déclaration de fonction de délégué a changé dans Swift 3.0. Nouvelle déclaration ici

b) La déclaration NSCharacterSet a changé.

 func textField(_ shouldChangeCharactersIntextField: UITextField, shouldChangeCharactersIn range: NSRange, replacementSsortingng ssortingng: Ssortingng) -> Bool { let inverseSet = NSCharacterSet(charactersIn:"0123456789").inverted let components = ssortingng.components(separatedBy: inverseSet) let filtered = components.joined(separator: "") return ssortingng == filtered } 
 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementSsortingng ssortingng: Ssortingng) -> Bool { let textSsortingng = (textField.text! as NSSsortingng).replacingCharacters(in: range, with: ssortingng) if textField == self.phoneTextField && ssortingng.characters.count > 0{ let numberOnly = NSCharacterSet.decimalDigits let strValid = numberOnly.contains(UnicodeScalar.init(ssortingng)!) return strValid && textSsortingng.characters.count <= 10 } return true } 

dans le code ci-dessus travaille dans 3 rapide
NSCharacterSet. numbers décimaux
Vous utilisez également des lettres seulement
NSCharacterSet. Des lettres
et majuscules, Lowercaseand, alphanumériques, whitespaces est utilisé le même code ou Voir le lien

 Swift 2.0 func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementSsortingng ssortingng: Ssortingng) -> Bool { let inverseSet = NSCharacterSet(charactersInSsortingng:"0123456789").invertedSet let components = ssortingng.componentsSeparatedByCharactersInSet(inverseSet) let filtered = components.joinWithSeparator("") return ssortingng == filtered } 

C'est une version plus lisible qui fera "0-9" plus ".":

 func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementSsortingng ssortingng: Ssortingng) -> Bool { let existingTextHasDecimal = textField.text?.rangeOfSsortingng(".") let replacementTextHasDecimal = ssortingng.rangeOfSsortingng(".") let replacementTextAllCharacters = NSCharacterSet(charactersInSsortingng: ssortingng) let replacementTextOnlyDigits = NSCharacterSet.decimalDigitCharacterSet().isSupersetOfSet(replacementTextAllCharacters) if replacementTextHasDecimal != nil && existingTextHasDecimal != nil { return false }else{ if replacementTextOnlyDigits == true { return true }else if replacementTextHasDecimal != nil{ return true }else{ return false } } } 
 func isValidNumber(str:Ssortingng) -> Bool{ if str.isEmpty { return false } let newChar = NSCharacterSet(charactersInSsortingng: str) let boolValid = NSCharacterSet.decimalDigitCharacterSet().isSupersetOfSet(newChar) if boolValid{ return true }else{ let lst = str.componentsSeparatedBySsortingng(".") let newStr = lst.joinWithSeparator("") let currentChar = NSCharacterSet(charactersInSsortingng: newStr) if lst.count == 2 && !lst.contains("") && NSCharacterSet.decimalDigitCharacterSet().isSupersetOfSet(currentChar){ return true } return false } } 

Mettez cette fonction dans votre méthode "Submit" ou "Save" s'il y en a une.

Vous pouvez utiliser shouldChangeCharactersInRange avec la méthode d'extension Ssortingng pour vérifier si la string d'input est number ou non.

 extension Ssortingng { var isNumber : Bool { get{ return !self.isEmpty && self.ssortingngWithoutWhitespaces.rangeOfCharacter(from: CharacterSet.decimalDigits.inverted) == nil } } var ssortingngWithoutWhitespaces: Ssortingng { return self.replacingOccurrences(of: " ", with: "") } } //Mark: shouldChangeCharactersInRange func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementSsortingng ssortingng: Ssortingng) -> Bool { // return true if the ssortingng only contains numeric characters let isValid = ssortingng.ssortingngWithoutWhitespaces.isNumber return valid } 

Solution simple pour les nombres Double (gardez à l'esprit que ce n'est pas la meilleure solution conviviale), dans votre délégué UITextFieldDelegate :

 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementSsortingng ssortingng: Ssortingng) -> Bool { guard let currentSsortingng = textField.text as NSSsortingng? else { return false } let newSsortingng = currentSsortingng.replacingCharacters(in: range, with: ssortingng) return Double(newSsortingng) != nil } 

J'ai édité la version de Raj Joshi pour permettre un point ou une virgule:

 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementSsortingng ssortingng: Ssortingng) -> Bool { let inverseSet = CharacterSet(charactersIn:"0123456789").inverted let components = ssortingng.components(separatedBy: inverseSet) let filtered = components.joined(separator: "") if filtered == ssortingng { return true } else { if ssortingng == "." || ssortingng == "," { let countDots = textField.text!.components(separatedBy:".").count - 1 let countCommas = textField.text!.components(separatedBy:",").count - 1 if countDots == 0 && countCommas == 0 { return true } else { return false } } else { return false } } } 

Vous pouvez utiliser ce code si vous souhaitez autoriser le séparateur décimal et / ou les nombres négatifs. Mais ce code permet un exemple: "34". (séparateur décimal à la fin) lors de la modification du text. Vous devez donc append un exemple de code: textFieldShouldReturn ou textFieldShouldEndEditing des fonctions de délégué.

Le code écrit dans Swift 4 mais je suppose que ceci est compatible avec Swift 3.

 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementSsortingng ssortingng: Ssortingng) -> Bool { guard let text = textField.text else { return true } let replaced = (text as NSSsortingng).replacingCharacters(in: range, with: ssortingng) let decimalSeparator = NSLocale.current.decimalSeparator ?? "" // When user wants to delete las character if replaced == "" || replaced == "-" || replaced == "-0" { textField.text = "0" return false } // When text contains 0 before replace except "0." if replaced != "0" + decimalSeparator && replaced.hasPrefix("0") && text.underestimatedCount == 1 { textField.text = replaced.subssortingng(from: replaced.index(after: replaced.startIndex)) return false } // When user wants to delete minus sign if text.hasPrefix("-") && text.subssortingng(from: text.index(after: text.startIndex)) == replaced { return false } // When user wants to delete before decimal separator if replaced.hasPrefix(decimalSeparator) || replaced.hasPrefix("-" + decimalSeparator) { return false } // When user wants to add zero the beginning of number... but allowing "0." or "-0." numbers let testReplaced = replaced.hasPrefix("-") ? replaced.subssortingng(from: replaced.index(after: replaced.startIndex)) : replaced if testReplaced.count >= 2 && testReplaced.hasPrefix("0") && !testReplaced.hasPrefix("0" + decimalSeparator) { return false } // Every other cases let allowDecimal = self.allowFloat ? (decimalSeparator == "." ? "\\.?" : decimalSeparator + "?") : "" let allowSign = self.allowSigned ? "-?" : "" let pattern = "\(allowSign)[0-9]+\(allowDecimal)([0-9]+)?" do { let regexRange = (replaced as NSSsortingng).range(of: replaced) let regex = try NSRegularExpression(pattern: pattern, options: []) let matches = regex.matches(in: replaced, options: [], range: regexRange) return matches.count == 1 && matches.first!.range == regexRange } catch {} return false } 

Si vous ne voulez pas autoriser les nombres décimaux ou négatifs, vous devez replace la variable de remorquage par la ligne suivante

 let allowDecimal = "" let allowSign = "" 

Tout d'abord append un delegate et keyBoradType de textField

textField.delegate=self; textField.keyboardType = UIKeyboardTypeNumberPad;

Que devoir utiliser la méthode textField.delegate comme si –

 - (BOOL) textField: (UITextField *)theTextField shouldChangeCharactersInRange:(NSRange)range replacementSsortingng: (NSSsortingng *)ssortingng { if (!ssortingng.length) { return YES; } if ([ssortingng intValue]) { return YES; } return NO; } 

Mise à jour de la réponse de Cian ci-dessus à Swift 3:

func textField(textField: UITextField,shouldChangeCharactersInRange range: NSRange,replacementSsortingng ssortingng: Ssortingng) -> Bool { let newCharacters = NSCharacterSet(charactersIn: ssortingng) let boolIsNumber = NSCharacterSet.decimalDigits.isSuperset(of:newCharacters as CharacterSet) if boolIsNumber == true { return true } else { if ssortingng == "." { let countdots = textField.text!.components(separatedBy:".").count - 1 if countdots == 0 { return true } else { if countdots > 0 && ssortingng == "." { return false } else { return true } } } else { return false } } }

// Accepte uniquement les nombres décimaux en input, [SWIFT 3.0]

 func textField(_ shouldChangeCharactersIntextField: UITextField, shouldChangeCharactersIn range: NSRange, replacementSsortingng ssortingng: Ssortingng) -> Bool { let inverseSet = NSCharacterSet(charactersIn:"0123456789").inverted let components = ssortingng.components(separatedBy: inverseSet) let filtered = components.joined(separator: "") return ssortingng == filtered }