Как лучше всего проверить ввод валюты в UITextField?
Автор вопроса: jpmОтветов: 12
Мое приложение позволяет пользователю вводить числовое значение (валюту) в элементе управления UITextField, но желаемая раскладка клавиатуры, к сожалению, не является одной из встроенных опций, поэтому мне пришлось выбрать опцию "Числа и пунктуация" в Интерфейсном Разработчике. Вот соответствующее диалоговое окно в IB:
Поэтому, когда мое приложение запрашивает у пользователя ввод, оно отображает следующее:
Это прекрасно, но посмотрите на все дополнительные ключи, доступные пользователю! Можно было легко ввести "12; 56!" в текстовом поле, и я предполагаю, что мне нужно как-то это проверить.
Итак, мой вопрос: как мне проверить значения валюты, введенные в UITextField?
Возможно, вы могли бы прикрепить UITextFieldDelegate к элементу управления и заставить его реализовать textField:shouldChangeCharactersInRange:replacementString:. Таким образом, если он увидит какие-либо символы, которые вам не нужны в поле, он сможет их отклонить. .
Ответ 2 · рейтинг 28 · Matthias Bauch
У меня есть желание ответить, потому что это была первая запись, которую я увидел, когда я погуглил, и ответ с самым высоким рейтингом не позволил мне ввести валюту. Я немец, и я из Германии (и во многих других странах) мы используем , в качестве десятичного разделителя.
Я только что написал похожий метод, и это то, что у меня есть прямо сейчас.
Я обнаружил, что это относительно чистый подход. Я не тестировал его с валютами, отличными от США, но, поскольку он использует свойства NSNumberFormatter, я считаю, что он должен обрабатывать их правильно.
Начните с настройки форматтера в каком-нибудь месте:
Используйте средство форматирования для анализа и переформатирования их ввода. Он также обрабатывает сдвиг числа при добавлении и удалении цифр.
-(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's 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 · рейтинг 7 · Matt Gallagher
В сочетании с предложением textField:shouldChangeCharactersInRange:replacementString:, сделанным Марком, вы должны передать текст через NSNumberFormatter, используя NSNumberFormatterCurrencyStyle. Это позволит справиться с особенностями форматирования валюты и обработать параметры, специфичные для локали.
Если вы его найдете, в документации iPhone есть раздел "Руководство по программированию форматирования данных для какао". К сожалению, большая часть информации о пользовательском интерфейсе здесь предназначена для Mac OS X (не работает на iPhone), но она покажет вам, как использовать классы форматирования.
Ответ 6 · рейтинг 6 · Ben Golding
Я обнаружил, что shouldChangeCharactersInRange также закручивает всплывающую клавиатуру, возврат и кнопку "Готово". Я обнаружил, что если я обрабатывал строки нулевой длины и разрешал управляющие символы, все работало нормально.
Мне не нравится использовать NSNumberFormatter, потому что он настаивает на том, чтобы число было правильно сформировано на всех этапах, пока пользователь редактирует, и это может привести в ярость, если вы, скажем, хотите иметь две десятичные точки в номере на мгновение, пока вы не удалите тот, что не в том месте.
Несколько неудачный код [[currencySet copy] autorelease] возвращает неизменный NSCharacterSet.
Использование [NSCharacterSet decimalDigitCharacterSet] также включает в себя индийские и арабские эквивалентные символы, что, надеюсь, означает, что люди, использующие эти языки, могут использовать цифры своего алфавита для ввода чисел.
По-прежнему необходимо проверить, может ли NSNumberFormatter анализировать ввод пользователя и предупреждать, если он не может; тем не менее, когда можно вводить только допустимые символы, это дает больше удовольствия.
Ответ 7 · рейтинг 5 · Thomas Tempelmann
Я все время вижу, что люди не знают, как правильно определить результирующую строку при реализации shouldChangeCharactersInRange.
Вот как вы получите новый текст, который будет введен, если вы ответите ДА:
Когда у вас есть этот новый текст, легко проверить, является ли этот текст допустимым числом или нет, и вернуть ДА или НЕТ соответственно.
Имейте в виду, что все другие решения, такие как показанные здесь, где проверяется длина "строки" и т. Д., Могут работать некорректно, если пользователь пытается отредактировать строку с помощью клавиатуры Bluetooth с клавишами управления курсором или с помощью дополнительных функции редактирования (выбрать, вырезать, вставить).
Ответ 8 · рейтинг 2 · Grouchal
Если вы хотите, чтобы они могли вводить только цифры - вы можете также рассмотреть цифровую клавиатуру.
Ответ 9 · рейтинг 2 · Brian L
Найдя быстрое решение проблемы переполнения стека для работы с валютой США, я переписал функцию для безопасной работы с международными валютами. Это решение будет динамически проверять ввод данных пользователем из 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 · рейтинг 1 · Marc Charbonneau
Использование NSNumberFormatter - правильный ответ. Он будет обрабатывать проверку и преобразовывать строку в правильный тип объекта и обратно.
Ответ 11 · рейтинг 1 · Aku
Вы также можете использовать решение Gamma-Point и оценить, равно ли * aNumber Nil, если его Nil, то это означает символ, который не был 0-9. или, было введено, таким образом вы можете проверять только числа, он обнулит переменную, если введен какой-либо символ без числа.
Ответ 12 · рейтинг 1 · supp-f
Не удалось найти подходящую реализацию для проверки валюты. Вот мой вариант:
- (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;
}