web-dev-qa-db-fra.com

Autoriser uniquement les nombres pour l'entrée UITextField

L'iPad n'a pas de clavier "Numpad", contrairement à l'iPhone/iPod.

Je cherche un moyen de restreindre le clavier de l'utilisateur à accepter uniquement les valeurs comprises entre 0 et 9.

J'imagine que je peux utiliser "shouldChangeCharactersInRange" de UITextField mais je ne connais pas le meilleur moyen de le mettre en œuvre.

70
Demasterpl

Voici comment j'ai géré le problème sur un champ de vérification SSN. Vous pouvez modifier la longueur maximale et supprimer l'instruction if en vérifiant le type de clavier si vous en avez besoin.

Il existe également une logique permettant de supprimer les alertes de longueur maximale lorsque l'utilisateur tape au lieu de coller des données.

Dans le contexte de ce code, BasicAlert() est une macro #define qui affiche simplement une variable UIAlertView ou UIAlertController à l'aide du titre et des chaînes de message transmises.

// NOTE: This code assumes you have set the UITextField(s)'s delegate property to the object that will contain this code, because otherwise it would never be called.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    // allow backspace
    if (!string.length)
    {
        return YES;
    }

    // Prevent invalid character input, if keyboard is numberpad
    if (textField.keyboardType == UIKeyboardTypeNumberPad)
    {
        if ([string rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet].invertedSet].location != NSNotFound)
        {
            // BasicAlert(@"", @"This field accepts only numeric entries.");
            return NO;
        }
    }

    // verify max length has not been exceeded
    NSString *proposedText = [textField.text stringByReplacingCharactersInRange:range withString:string];

    if (proposedText.length > 4) // 4 was chosen for SSN verification
    {
        // suppress the max length message only when the user is typing
        // easy: pasted data has a length greater than 1; who copy/pastes one character?
        if (string.length > 1)
        {
            // BasicAlert(@"", @"This field accepts a maximum of 4 characters.");
        }

        return NO;
    }

    // only enable the OK/submit button if they have entered all numbers for the last four of their SSN (prevents early submissions/trips to authentication server)
    self.answerButton.enabled = (proposedText.length == 4);

    return YES;
}
68
Thuggish Nuggets

Vous pouvez utiliser ce code pour n'autoriser que le nombre dans textField.

Avant cela, définir le délégué pour textField

      textFieldName.delegate=self;

ou

      [textFieldName setDelegate:self];

Puis utilisez ce code pour n’autoriser que digit to textField

      - (BOOL) textField: (UITextField *)theTextField shouldChangeCharactersInRange:(NSRange)range replacementString: (NSString *)string {
//return yes or no after comparing the characters

      // allow backspace
      if (!string.length)
      {
           return YES;
      }

      ////for Decimal value start//////This code use use for allowing single decimal value
      //    if ([theTextField.text rangeOfString:@"."].location == NSNotFound)
      //    {
      //        if ([string isEqualToString:@"."]) {
      //            return YES;
      //        }
      //    }
      //    else
      //    {
      //        if ([[theTextField.text substringFromIndex:[theTextField.text rangeOfString:@"."].location] length]>2)   // this allow 2 digit after decimal 
      //        {
      //            return NO;
      //        }
      //    }
      ////for Decimal value End//////This code use use for allowing single decimal value

      // allow digit 0 to 9
      if ([string intValue])
      {
            return YES;
      }

      return NO;
    }
25
Aje

Étapes très spécifiques pour le code Swift

Vous pouvez fournir une logique qui limite l'entrée du champ de texte dans la méthode func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool en implémentant le protocole UITextFieldDelegate.

Par souci de clarté, ces étapes supposent que votre storyboard contienne un objet View Controller avec un objet text field ne pouvant accepter que des chiffres.

  1. Créez une classe personnalisée pour le contrôleur de vue qui étend UIViewController. Assurez-vous que la scène de votre storyboard fait référence à la classe personnalisée en définissant la valeur de la classe personnalisée dans l'inspecteur d'identité de Xcode.

    import UIKit
    class YourCustomController: UIViewController {
        override func viewDidLoad() {        
            super.viewDidLoad()
        }
    }
    
  2. Créez un point de vente à partir du champ de texte de votre scène sur votre contrôleur de vue personnalisé.

    class YourCustomController: UIViewController {
        @IBOutlet weak var numberField: UITextField!
        ...
    }
    
  3. Appliquez le protocole UITextFieldDelegate dans votre contrôleur de vue personnalisé.

    class YourCustomController: UIViewController, UITextFieldDelegate {
        ...
    }
    
  4. Dans la méthode viewDidLoad de votre contrôleur de vue personnalisé, affectez le délégué de votre champ de texte à la classe de votre contrôleur de vue personnalisé.

    override func viewDidLoad() {        
        super.viewDidLoad()
        numberField.delegate = self
    }
    
  5. Ajoutez la méthode UITextFieldDelegate 's func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool

    En faisant de votre contrôleur de vue personnalisé le délégué de la numberField à l'étape précédente, cette méthode sera appelée chaque fois qu'un utilisateur saisit un caractère dans le champ de texte. Si votre méthode retourne true, le caractère restera dans le champ de texte. Si votre méthode retourne false, le caractère pas restera dans le champ de texte.

    Le paramètre string est le caractère saisi par l'utilisateur. Si le caractère string peut être converti en Int, il est compris entre 0 et 9; sinon, il s'agit d'un caractère non numérique.

    class YourCustomController: UIViewController, UITextFieldDelegate {
        ...
        func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    
            return Int(string) != nil
        }
    }
    

(Voir ci-dessous pour le code complet du contrôleur.)


Exemple de contrôleur de vue avec un champ de texte à chiffres uniquement

import UIKit

class YourCustomController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var numberField: UITextField!

    override func viewDidLoad() {        
        super.viewDidLoad()       
        numberField.delegate = self
    }

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

Exemple de contrôleur de vue avec un champ de texte décimal

Si vous souhaitez prendre en charge un nombre décimal, utilisez NSNumberFormatter. Voir les commentaires de code pour les différences.

import UIKit

class YourCustomController: UIViewController, UITextFieldDelegate {

    @IBOutlet weak var numberField: UITextField!

    private var formatter: NSNumberFormatter!

    override func viewDidLoad() {        
        super.viewDidLoad()       
        numberField.delegate = self

        // Initialize the formatter; minimum value is set to zero; style is Decimal. 
        formatter = NSNumberFormatter()
        formatter.numberStyle = NSNumberFormatterStyle.DecimalStyle
        formatter.minimum = 0
    }

    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
        // Combine the current text field value and the new string
        // character. If it conforms to the formatter's settings then
        // it is valid. If it doesn't then nil is returned and the
        // string character should not be allowed in the text field.         
        return formatter.numberFromString("\(textField.text)\(string)") != nil
    }    
}
17
whyceewhite

Essayez ceci pour éviter le problème de compensation de champ de texte 

Swift 3.0

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    guard NSCharacterSet(charactersInString: "0123456789").isSupersetOfSet(NSCharacterSet(charactersInString: string)) else {
        return false
    }
    return true
}

Swift 4.0

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    guard CharacterSet(charactersIn: "0123456789").isSuperset(of: CharacterSet(charactersIn: string)) else {
        return false
    }
    return true
}
15
SPatel
- (BOOL) textField: (UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString: (NSString *)string {

    NSNumberFormatter * nf = [[NSNumberFormatter alloc] init];
    [nf setNumberStyle:NSNumberFormatterNoStyle];

    NSString * newString = [NSString stringWithFormat:@"%@%@",textField.text,string];
    NSNumber * number = [nf numberFromString:newString];

    if (number)
        return YES;
    else
       return NO;
}
8
Adobels

J'ai appliqué ça et ça marche !!

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
// Check for non-numeric characters
NSUInteger lengthOfString = string.length;
for (NSInteger index = 0; index < lengthOfString; index++) {
    unichar character = [string characterAtIndex:index];
    if (character < 48) return NO; // 48 unichar for 0
    if (character > 57) return NO; // 57 unichar for 9
}
// Check total length for restrict user
NSUInteger proposedNewLength = textField.text.length - range.length + string.length;
if (proposedNewLength > 6)
    return YES;
return YES;                                                                                                                                     
}
6
iDev
Works fine for me :

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (([string rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]].location != NSNotFound) && !(range.length==1 && string.length==0)) {
            return NO;
        }
        return YES;
    }
2
Ankit Kumar Gupta
NSString* val = [[textField text] stringByReplacingCharactersInRange:range withString:string];
    NSCharacterSet *allowedCharacterSet = [NSCharacterSet decimalDigitCharacterSet];
    if ([[string componentsSeparatedByCharactersInSet:[allowedCharacterSet invertedSet]] count] > 1 || [val length] > 5) {
        return NO;
    }
2
johnny

Swift 3

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    if textField==yourTextFieldOutlet {
                if(CharacterSet.decimalDigits.isSuperset(of: CharacterSet(charactersIn: yourTextFieldOutlet.text!))){
//if numbers only, then your code here
                }
                else{
                showAlert(title: "Error",message: "Enter Number only",type: "failure")
                }
            }
    return true
    }
0
ArgaPK

Si vous utilisez mon modèle specification , le code ressemble à ceci

textField.delegate = self

lazy var specification: Specification = {
    return RegularExpressionSpecification(pattern: "^(|0|[1-9]\\d{0,6})$")
}()

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let textFieldString: NSString = textField.text ?? ""
    let s = textFieldString.stringByReplacingCharactersInRange(range, withString:string)
    return specification.isSatisfiedBy(s)
}

func textFieldShouldReturn(textField: UITextField) -> Bool {
    let s = textField.text ?? ""
    let isTextValid = specification.isSatisfiedBy(s)
    if isTextValid {
        textField.resignFirstResponder()
    }
    return false
}
0
neoneye

J'ai modifié la réponse de @ iDev pour qu'elle fonctionne avec les chiffres et ".":

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
     // Check for non-numeric characters
     NSUInteger lengthOfString = string.length;
     for (NSInteger index = 0; index < lengthOfString; index++) {
         unichar character = [string characterAtIndex:index];
         if ((character < 48) && (character != 46)) return NO; 
         // 48 unichar for 0, and 46 unichar for point
         if (character > 57) return NO; 
         // 57 unichar for 9
     }
     // Check for total length
     NSUInteger proposedNewLength = textField.text.length - range.length + string.length;
     if (proposedNewLength > 6)
         return YES;
     return YES; 
 }
0
Darius Miliauskas

Conservez des données de présentation distinctes de la représentation interne. Il y a un moyen plus simple. Laissez NSNumberFormatter faire le travail:

 NSNumberFormatter* ns = [[NSNumberFormatter alloc] init];
 ns.numberStyle = NSNumberFormatterDecimalStyle;
 [ns setMaximumFractionDigits:2];
 // This is your internal representation of the localized number
 double a = [[ns numberFromString:self.textIVA.text] doubleValue]];

[mylabel setText:[NSString stringWithFormat:@"€ %@",
     [NSNumberFormatter localizedStringFromNumber:
                          [NSNumber numberWithDouble:a]
                                      numberStyle:NSNumberFormatterDecimalStyle]]];
0
giuseppe