Каков наилучший способ проверки ввода валюты в UITextField?
Мое приложение позволяет пользователю вводить числовое значение (валюта) в элементе управления UITextField
, но расположение клавиатуры, которое я желаю, доступно, к сожалению, не является одним из встроенных параметров, поэтому мне пришлось выбрать "Numbers and Punctuation" в интерфейсе Builder. Здесь соответствующее диалоговое окно в IB:
http://pessoal.org/interface_builder_kb.png
Итак, когда мое приложение запрашивает у пользователя ввод, оно отображает следующее:
http://pessoal.org/app_kb.png
Это прекрасно, но посмотрите на все дополнительные ключи, доступные пользователю! Легко войти в "12; 56!" в текстовом поле, и я предполагаю, что мне нужно как-то это проверить.
Итак, мой вопрос: как проверить значения валюты, введенные в UITextField
?
Ответы
Ответ 1
Возможно, вы могли бы прикрепить UITextFieldDelegate
к элементу управления и реализовать его textField:shouldChangeCharactersInRange:replacementString:
. Таким образом, если он видит любые символы, которые вы не хотите в поле, оно может отклонить их.
Ответ 2
У меня есть желание ответить, потому что это была первая запись, которую я видел, когда я искал googled, и самый высокий рейтинг не позволил мне ввести валюту.
Я немецкий, а в Германии (и во многих других странах) мы используем ,
как decimalseparator.
Я просто написал подобный метод, и это то, что я имею прямо сейчас.
- (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
static NSString *numbers = @"0123456789";
static NSString *numbersPeriod = @"01234567890.";
static NSString *numbersComma = @"0123456789,";
//NSLog(@"%d %d %@", range.location, range.length, string);
if (range.length > 0 && [string length] == 0) {
// enable delete
return YES;
}
NSString *symbol = [[NSLocale currentLocale] objectForKey:NSLocaleDecimalSeparator];
if (range.location == 0 && [string isEqualToString:symbol]) {
// decimalseparator should not be first
return NO;
}
NSCharacterSet *characterSet;
NSRange separatorRange = [textField.text rangeOfString:symbol];
if (separatorRange.location == NSNotFound) {
if ([symbol isEqualToString:@"."]) {
characterSet = [[NSCharacterSet characterSetWithCharactersInString:numbersPeriod] invertedSet];
}
else {
characterSet = [[NSCharacterSet characterSetWithCharactersInString:numbersComma] invertedSet];
}
}
else {
// allow 2 characters after the decimal separator
if (range.location > (separatorRange.location + 2)) {
return NO;
}
characterSet = [[NSCharacterSet characterSetWithCharactersInString:numbers] invertedSet];
}
return ([[string stringByTrimmingCharactersInSet:characterSet] length] > 0);
}
Ответ 3
Пока вы можете указывать в NSNumberFormatter, мне было проще просто отключить что-либо, кроме 0-9 и.
Это хорошо работает для меня:
- (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSCharacterSet *nonNumberSet = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789."] invertedSet];
return ([string stringByTrimmingCharactersInSet:nonNumberSet].length > 0);
}
код >
Ответ 4
Я считаю, что это относительно чистый подход. Я не тестировал его с неамериканскими валютами, но поскольку он использует свойства NSNumberFormatter, я считаю, что он должен правильно их обрабатывать.
Начните с настройки форматирования в некотором месте:
formatter = [NSNumberFormatter new];
[formatter setNumberStyle: NSNumberFormatterCurrencyStyle];
[formatter setLenient:YES];
[formatter setGeneratesDecimalNumbers:YES];
Используйте форматтер для разбора и форматирования их ввода. Он также обрабатывает смещение числа, когда цифры добавляются и удаляются.
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *replaced = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSDecimalNumber *amount = (NSDecimalNumber*) [formatter numberFromString:replaced];
if (amount == nil) {
// Something screwed up the parsing. Probably an alpha character.
return NO;
}
// If the field is empty (the initial case) the number should be shifted to
// start in the right most decimal place.
short powerOf10 = 0;
if ([textField.text isEqualToString:@""]) {
powerOf10 = -formatter.maximumFractionDigits;
}
// If the edit point is to the right of the decimal point we need to do
// some shifting.
else if (range.location + formatter.maximumFractionDigits >= textField.text.length) {
// If there a range of text selected, it'll delete part of the number
// so shift it back to the right.
if (range.length) {
powerOf10 = -range.length;
}
// Otherwise they're adding this many characters so shift left.
else {
powerOf10 = [string length];
}
}
amount = [amount decimalNumberByMultiplyingByPowerOf10:powerOf10];
// Replace the value and then cancel this change.
textField.text = [formatter stringFromNumber:amount];
return NO;
}
Ответ 5
В сочетании с предложением textField:shouldChangeCharactersInRange:replacementString:
, сделанным Marc, вы должны передать текст через NSNumberFormatter
с помощью NSNumberFormatterCurrencyStyle
. Это будет обрабатывать причуды форматирования валюты и обрабатывать специфические для локали варианты.
В документации iPhone вы найдете "Руководство по программированию форматирования данных для Cocoa", если вы его ищете. К сожалению, большая часть информации пользовательского интерфейса здесь - это Mac OS X (не работает на iPhone), но она покажет вам, как использовать классы форматирования.
Ответ 6
Я обнаружил, что mustChangeCharactersInRange закручивает всплывающие клавиши, backspace и кнопку "Done". Я обнаружил, что если я обработал 0 строк длины и допустил управляющие символы, он работал нормально.
Мне не нравится использовать NSNumberFormatter, потому что он настаивает на том, что число хорошо сформировано на всех этапах, пока пользователь редактирует, и это может быть бесит, если вы, скажем, хотите на мгновение иметь две десятичные точки в номере пока вы не удалите тот, который находится в неправильном месте.
Вот код, который я использовал:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if ([string length] < 1) // non-visible characters are okay
return YES;
if ([string stringByTrimmingCharactersInSet:[NSCharacterSet controlCharacterSet]].length == 0)
return YES;
return ([string stringByTrimmingCharactersInSet:[self.characterSet invertedSet]].length > 0);
}
Если self.characterSet содержит допустимые символы, я использовал этот метод для его создания для валюты:
- (NSCharacterSet *)createCurrencyCharacterSet
{
NSLocale *locale = [NSLocale currentLocale];
NSMutableCharacterSet *currencySet = [NSMutableCharacterSet decimalDigitCharacterSet];
[currencySet addCharactersInString:@"-"]; // negative symbol, can't find a localised version
[currencySet addCharactersInString:[locale objectForKey:NSLocaleCurrencySymbol]];
[currencySet addCharactersInString:[locale objectForKey:NSLocaleGroupingSeparator]];
[currencySet addCharactersInString:[locale objectForKey:NSLocaleDecimalSeparator]];
return [[currencySet copy] autorelease];
}
Несколько несчастливый код [[currencySet copy] autorelease]
возвращает неизменяемый NSCharacterSet.
Использование [NSCharacterSet decimalDigitCharacterSet]
также включает символы индикатора и арабского эквивалента, которые, мы надеемся, означают, что люди используют эти языки, могут использовать свои цифры в алфавите для ввода чисел.
По-прежнему необходимо проверить, что NSNumberFormatter может анализировать пользовательский ввод и предупреждение, если он не может; тем не менее, он дает приятный опыт, когда могут вводиться только допустимые символы.
Ответ 7
Я все время вижу, что люди не знают, как правильно определить результирующую строку при реализации shouldChangeCharactersInRange.
Вот как вы получите новый текст, который будет введен, если вы вернетесь ДА:
NSString *newText = [textField.text stringByReplacingCharactersInRange:range withString:string];
После того, как у вас есть этот новый текст, легко проверить, является ли этот текст допустимым числом или нет, и соответственно вернуть ДА или НЕТ.
Имейте в виду, что все другие решения, такие как показанные здесь, где один проверяет длину "строки" и т.д., могут не работать должным образом, если пользователь пытается отредактировать строку с помощью клавиатуры bluetooth с помощью клавиш курсора или используя расширенные функции редактирования (выберите, вырежьте, вставьте).
Ответ 8
Если вы хотите, чтобы они могли вводить только цифры, вы также можете рассмотреть цифровую клавиатуру
Ответ 9
После нахождения быстрого решения о переполнении стека для обработки валюты США, я переписал эту функцию, чтобы безопасно обрабатывать международные валюты. Это решение будет динамически проверять ввод пользователя из UITextField, исправляя по мере их ввода.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
[numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[numberFormatter setMaximumFractionDigits:2];
[numberFormatter setMinimumFractionDigits:0];
// Grab the contents of the text field
NSString *text = [textField text];
// the appropriate decimalSeperator and currencySymbol for the current locale
// can be found with help of the
// NSNumberFormatter and NSLocale classes.
NSString *decimalSeperator = numberFormatter.decimalSeparator;
NSString *currencySymbol = numberFormatter.currencySymbol;
NSString *replacementText = [text stringByReplacingCharactersInRange:range withString:string];
NSMutableString *newReplacement = [[ NSMutableString alloc ] initWithString:replacementText];
// whenever a decimalSeperator or currencySymobol is entered, we'll just update the textField.
// whenever other chars are entered, we'll calculate the new number and update the textField accordingly.
// If the number can't be computed, we ignore the new input.
NSRange decimalRange = [text rangeOfString:decimalSeperator];
if ([string isEqualToString:decimalSeperator] == YES &&
[text rangeOfString:decimalSeperator].length == 0) {
[textField setText:newReplacement];
} else if([string isEqualToString:currencySymbol] == YES&&
[text rangeOfString:currencySymbol].length == 0) {
[textField setText:newReplacement];
} else if([newReplacement isEqualToString:currencySymbol] == YES) {
return YES;
}else {
NSString *currencyGroupingSeparator = numberFormatter.currencyGroupingSeparator;
[newReplacement replaceOccurrencesOfString:currencyGroupingSeparator withString:@"" options:NSBackwardsSearch range:NSMakeRange(0, [newReplacement length])];
[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
NSNumber *number = [numberFormatter numberFromString:newReplacement];
if([newReplacement length] == 1) {
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
number = [numberFormatter numberFromString:newReplacement];
}
if (number == nil) {
[newReplacement release];
return NO;
}
[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
text = [numberFormatter stringFromNumber:number];
[textField setText:text];
}
[newReplacement release];
return NO; // we return NO because we have manually edited the textField contents.
}
Ответ 10
Использование NSNumberFormatter - правильный ответ. Он будет обрабатывать проверку и преобразование строки в правильный тип объекта и из него.
Ответ 11
Вы также можете использовать решение Gamma-Point и оценить, если * aNumber - Nil, если его Nil, то это означает, что символ не был 0-9. или, было введено, таким образом, вы можете проверить только числа, это будет ноль переменной, если будет введено любое число no char.
Ответ 12
I Не удалось найти подходящую реализацию для проверки валюты. Вот мой вариант:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString* proposedString = [textField.text stringByReplacingCharactersInRange:range withString:string];
//if there is empty string return YES
if([proposedString length] == 0) {
return YES;
}
//create inverted set for appripriate symbols
NSCharacterSet *nonNumberSet = [[NSCharacterSet characterSetWithCharactersInString:@"0123456789.,"] invertedSet];
//if side symbols is trimmed by nonNumberSet - return NO
if([proposedString stringByTrimmingCharactersInSet:nonNumberSet].length != [proposedString length]) {
return NO;
}
//if there is more than 1 symbol of '.' or ',' return NO
if([[proposedString componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@".,"]] count] > 2) {
return NO;
}
//finally check is ok, return YES
return YES;
}
Ответ 13
Использование shouldChangeCharactersInRange закручивает всплывающую клавиатуру, поскольку кнопка backspace не работает.
Форматирование чисел - путь. Здесь образец, который я использовал, чтобы найти положительные десятичные числа. Я называю это во время проверки проверки, например. когда пользователь нажимает кнопку сохранения.
-(BOOL) isPositiveNumber: (NSString *) numberString {
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber *aNumber = [numberFormatter numberFromString:numberString];
[numberFormatter release];
if ([aNumber floatValue] > 0) {
NSLog( @"Found positive number %4.2f",[aNumber floatValue] );
return YES;
}
else {
return NO;
}
}