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.
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;
}
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;
}
É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.
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()
}
}
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!
...
}
Appliquez le protocole UITextFieldDelegate
dans votre contrôleur de vue personnalisé.
class YourCustomController: UIViewController, UITextFieldDelegate {
...
}
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
}
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
}
}
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
}
- (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;
}
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;
}
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;
}
NSString* val = [[textField text] stringByReplacingCharactersInRange:range withString:string];
NSCharacterSet *allowedCharacterSet = [NSCharacterSet decimalDigitCharacterSet];
if ([[string componentsSeparatedByCharactersInSet:[allowedCharacterSet invertedSet]] count] > 1 || [val length] > 5) {
return NO;
}
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
}
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
}
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;
}
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]]];