2012-02-18 3 views
12

Innanzitutto, ho configurato la tastiera per UITextField per utilizzare il numero con lo stile decimale. Quindi l'utente può inserire solo numeri e un singolo decimale.Come testare l'input di caratteri su UITextField quando l'utente immette caratteri e impedisce caratteri non validi

Quello che voglio fare è testare l'input mentre l'utente lo inserisce e impedire l'inserimento di più decimali e limitare la porzione decimale del numero a due posti. Non voglio arrotondare il numero né considerare l'input come un numero. Voglio semplicemente impedire all'utente di inserire più di due cifre a destra della virgola.

risposta

45

La soluzione alla fine si è rivelata piuttosto banale. Sfortunatamente molte domande e risposte relative a questa domanda riguardano la convalida o la formattazione di valori numerici, non che controllano ciò che un utente può immettere.

La seguente implementazione del metodo delegato shouldChangeCharactersInRange è la mia soluzione. Come sempre, le espressioni regolari oscillano in questa situazione. RegExLib.com è un'ottima fonte per utili campioni o soluzioni RegEx. Non sono un guru RegEx e faccio sempre fatica a metterli insieme, quindi ogni suggerimento per migliorarlo è il benvenuto.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string 
{ 
    if (textField == self.quantityTextField) 
    { 
     NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string]; 

     NSString *expression = @"^([0-9]+)?(\\.([0-9]{1,2})?)?$"; 

     NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:expression 
                       options:NSRegularExpressionCaseInsensitive 
                       error:nil]; 
     NSUInteger numberOfMatches = [regex numberOfMatchesInString:newString 
                  options:0 
                   range:NSMakeRange(0, [newString length])];   
     if (numberOfMatches == 0) 
      return NO;   
    } 

    return YES; 
} 

Il codice sopra permette all'utente di inserire questi tipi di valori: 1, 1.1, 1.11, .1, .11. Si noti che questa implementazione non sostituisce la stringa del campo di testo, il che causerebbe una ricorsione. Questa soluzione rifiuta semplicemente il prossimo carattere che l'utente inserisce se "newString" non corrisponde alla regex.

+0

funziona come un fascino! – Breakpoint

+0

ciao! Grazie! la tua risposta è molto utile. Ma come disabilitare "." e ","?? – Frade

+1

Frade, volevo che l'utente fosse in grado di usare ".". Dovresti essere in grado di impostare il keyboardType di textField su UIKeyboardTypeNumberPad. Questa tastiera non include la punteggiatura. – Seamus

3

Il modo standard di gestire questo problema in iOS è allegare un UITextFieldDelegate al numero UITextField e implementare il metodo textField:shouldChangeCharactersInRange:replacementString:. All'interno di questo metodo è possibile verificare che la stringa sia della "forma" corretta per i propri scopi (un punto, non più di due cifre dopo il punto, ecc.) E fornire una stringa diversa se l'input non segue il formato previsto.

-1

È possibile passare la stringa di uitexfield al di sotto del metodo, tornerà sì/no..accordingly è possibile mostrare errore

- (BOOL) validatePhone: (NSString *) aMobile { 
    NSString *phoneRegex = @"^+(?:[0-9] ?){6,14}[0-9]$"; 
    NSPredicate *phoneTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", phoneRegex]; 
    if (aMobile.length>0) { 
     NSString *mobileTextString = [[mobileText.text componentsSeparatedByCharactersInSet: 
             [[NSCharacterSet decimalDigitCharacterSet] invertedSet]] 
             componentsJoinedByString:@""]; 
     NSString *firstNumber = [aMobile substringToIndex:1]; 
     if (mobileTextString.length!=10){ 

      return NO; 
     } 

    } 
     return [phoneTest evaluateWithObject:aMobile]; 
} 
+0

Non ho guardato questo è un tempo lungo. L'obiettivo era impedire all'utente di inserire caratteri non validi. Non eseguire la convalida dopo il fatto. – Seamus

5

Buono! Se qualcuno ha bisogno di lavoro con le valute non statunitensi: euro o altri quelli con frazione separati da virgola invece di utilizzo dot questo:

NSString *expression = @"^([0-9]+)?([\\,\\.]([0-9]{1,2})?)?$"; 

L'unica differenza è che permette virgola o punto. ([\, \.] - o. o,) Unico trucco è che è necessario sostituire la virgola con il punto quando si utilizza il numero acquisito, perché il computer usa il punto per separare la frazione, non la virgola.

+0

Come si modifica la regex precedente per consentire il carattere meno all'inizio? Ad esempio, mi piacerebbe accettare numeri come -100.50 – melsam

1

Dopo molte sperimentazioni e guardando le soluzioni di altri (che sembrano eccessivamente complesse e laboriose) mi è venuto in mente il seguente, che impedisce all'utente di inserire qualsiasi cosa eccetto un importo in valuta valido. In sostanza, lasciare che un'istanza di NSNumberFormatter (creata in altre parti del viewController) fare il lavoro duro:

  • 1) convertire il testo in un numero (se nullo, poi ci sono caratteri non validi, in modo da tornare NO)
  • 2) quindi convertire il numero di valuta
  • 3) quindi convertire la stringa valuta ritorna numero e, se diverso dall'originale (mezzi troppi decimali immessi), restituire NO
  • 4), poi un NSDecimalNumber, che è quello che volevo. Potrebbe essere diverso per te, ovviamente. Lavora per me finora - spero che questo aiuti qualcuno.

In primo luogo, ho impostato la tastiera su UIKeyboardTypeDecimalPad. Poi ho usato il seguente codice

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string 

NSString *textString = [textField.text stringByReplacingCharactersInRange:range withString:string]; 

[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle]; 
NSNumber *amountNumber = [numberFormatter numberFromString:textString]; 

if ([textString length] > 0) { 
    if (!amountNumber) { 
     return NO; 
    } 
} else { 
    amountNumber = @0; 
} 


[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; 
NSString *amountStringer = [numberFormatter stringFromNumber:amountNumber]; 
NSNumber *amountAgain = [numberFormatter numberFromString:amountStringer]; 

// 
//make sure that the number obtained again is the same....prevents too many decimals.... 
if (![amountNumber isEqualToNumber:amountAgain]) { 
    return NO; 
} 

[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle]; 
amountShow.text = amountStringer; 

self.amount = [NSDecimalNumber decimalNumberWithDecimal:[amountAgain decimalValue]]; 
NSLog(@"decimal Amount is %@", self.amount); 

return YES; 

}

0

Per Swift 4 risposta principale della domanda è

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { 
    guard textField == quantityTextField, let textFieldString = textField.text as NSString? else { 
     return true 
    } 

    let newString = textFieldString.replacingCharacters(in: range, with: string) 
    let expression = "^([0-9]+)?(\\.([0-9]{1,2})?)?$" 

    let regex = try? NSRegularExpression(pattern: expression, options: .caseInsensitive) 
    let numberOfMathces = regex?.numberOfMatches(in: newString, options: NSRegularExpression.MatchingOptions(rawValue: 0), range: NSMakeRange(0, newString.characters.count)) 

    if numberOfMathces == 0 { 
     return false 
    } 

    return true 
}