Qual é a melhor maneira de inserir valores numéricos com pontos decimais?

No meu aplicativo, os usuários precisam inserir valores numéricos com casas decimais. O iPhone não possui um teclado específico para essa finalidade – apenas um teclado numérico e um teclado com números e símbolos.

Existe uma maneira fácil de usar o último e impedir que qualquer input não numérica seja inserida sem ter que regexar o resultado final?

Obrigado!

Uma solução mais elegante também é a mais simples.

Você não precisa de uma chave de separação decimal

Por quê? Porque você pode simplesmente inferir a partir da input do usuário. Por exemplo, no código de idioma dos EUA, quando você entra em US $ 1,23, comece digitando os números 1-2-3 (nessa ordem). No sistema, como cada caractere é inserido, isso seria reconhecido como:

  • usuário entra em 1: US $ 0,01
  • usuário entra 2: $ 0,12
  • usuário entra em 3: $ 1,23

Observe como inferimos o separador decimal com base na input do usuário. Agora, se o usuário quiser entrar em $ 1,00, basta digitar os números 1-0-0.

Para que seu código manipule moedas de uma localidade diferente, você precisa obter os dígitos da fração máxima da moeda. Isso pode ser feito com o seguinte trecho de código:

NSNumberFormatter *currencyFormatter = [[NSNumberFormatter alloc] init]; [currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; int currencyScale = [currencyFormatter maximumFractionDigits]; 

Por exemplo, o iene japonês tem um dígito de fração máxima de 0. Assim, ao lidar com a input de ienes, não há separador decimal e, portanto, não há necessidade de se preocupar com quantidades fracionárias.

Essa abordagem do problema permite que você use o teclado numérico de input de estoque fornecido pela Apple sem as dores de cabeça de teclados personalizados, validação de regex, etc.

Eu acho que seria bom ressaltar que a partir do iOS 4.1 você pode usar o novo UIKeyboardTypeDecimalPad .

Então agora você só precisa:

 myTextField.keyboardType=UIKeyboardTypeDecimalPad; 

Aqui está um exemplo para a solução sugerida na resposta aceita. Isso não lida com outras moedas ou qualquer coisa – no meu caso, eu só precisava de suporte para dólares, não importando o local / moeda, o que era bom para mim:

 -(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { double currentValue = [textField.text doubleValue]; //Replace line above with this //double currentValue = [[textField text] substringFromIndex:1] doubleValue]; double cents = round(currentValue * 100.0f); if ([string length]) { for (size_t i = 0; i < [string length]; i++) { unichar c = [string characterAtIndex:i]; if (isnumber(c)) { cents *= 10; cents += c - '0'; } } } else { // back Space cents = floor(cents / 10); } textField.text = [NSString stringWithFormat:@"%.2f", cents / 100.0f]; //Add this line //[textField setText:[NSString stringWithFormat:@"$%@",[textField text]]]; return NO; } 

As rodadas e os pisos são importantes a) por causa da representação de ponto flutuante às vezes perdendo .00001 ou qualquer outra coisa e b) a string de formato arredondando toda precisão que deletamos na parte de backspace.

Eu queria fazer exatamente a mesma coisa, exceto com moedas, em vez de valores decimais retos.

Acabei criando uma visualização personalizada que contém um UITextField e um UILabel. A etiqueta cobre o campo de texto, mas o campo de texto ainda recebe toques. Eu uso a notificação UITextFieldTextDidChange para observar as alterações no campo de texto (e eu usei um NSNumberFormatter para transformar o número resultante em um valor de moeda formatado) para atualizar o label.

Para desativar a lupa que permite ao usuário reposicionar o ponto de inserção, você precisará usar uma subclass UITextField personalizada e replace touchesBegan: withEvent: e configurá-la para não fazer nada.

Minha solução pode ser diferente da que você precisa porque o ponto decimal é sempre fixo – eu uso a configuração de moeda do sistema para determinar quantos dígitos devem existir após o ponto decimal. No entanto, o teclado numérico não possui um ponto decimal. E você não pode adicionar nenhum botão ao teclado (o que é especialmente agravante porque há um botão em branco no canto inferior esquerdo do teclado que seria perfeito para um ponto decimal!) Então eu não tenho uma solução para isso infelizmente.

Dependendo do aplicativo específico, fornecer um controle deslizante para o qual o usuário pode selecionar uma posição pode ser uma opção melhor no iPhone. Então, nenhum dígito precisa ser inserido.

Você pode querer usar um controle deslizante (como sugerido por Martin v. Löwis) ou um UIPickerView com uma roda separada para cada um dos dígitos.

Eu construí um controlador de visualização pad numérico personalizado com ponto decimal … confira:

http://sites.google.com/site/psychopupnet/iphone-sdk/tenkeypadcustom10-keypadwithdecimal

No iOS4.1, há um novo tipo de teclado UIKeyboardTypeNumberPad, mas, infelizmente, até o momento ele não parece aparecer na lista de opções do Interface Builder.

Veja como fazer isso sem usar floats, round () ou ceil () de uma maneira não monetária.

No controlador de visualização, configure as seguintes variables ​​de instância (com instruções @property associadas, se essa for sua mala):

 @interface MyViewController : UIViewController  { @private UITextField *firstResponder; NSNumberFormatter *formatter; NSInteger currencyScale; NSString *enteredDigits; } @property (nonatomic, readwrite, assign) UITextField *firstResponder; @property (nonatomic, readwrite, retain) NSNumberFormatter *formatter; @property (nonatomic, readwrite, retain) NSString *enteredDigits; @end 

e seu método viewDidLoad deve conter o seguinte:

 - (void)viewDidLoad { [super viewDidLoad]; NSNumberFormatter *aFormatter = [[NSNumberFormatter alloc] init]; [aFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; currencyScale = -1 * [aFormatter maximumFractionDigits]; self.formatter = aFormatter; [aFormatter release]; } 

Em seguida, implemente seus methods UITextFieldDelegate da seguinte maneira:

 #pragma mark - #pragma mark UITextFieldDelegate methods - (void)textFieldDidBeginEditing:(UITextField *)textField { // Keep a pointer to the field, so we can resign it from a toolbar self.firstResponder = textField; self.enteredDigits = @""; } - (void)textFieldDidEndEditing:(UITextField *)textField { if ([self.enteredDigits length] > 0) { // Get the amount NSDecimalNumber *result = [[NSDecimalNumber decimalNumberWithString:self.enteredDigits] decimalNumberByMultiplyingByPowerOf10:currencyScale]; NSLog(@"result: %@", result); } } - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { // Check the length of the string if ([string length]) { self.enteredDigits = [self.enteredDigits stringByAppendingFormat:@"%d", [string integerValue]]; } else { // This is a backspace NSUInteger len = [self.enteredDigits length]; if (len > 1) { self.enteredDigits = [self.enteredDigits substringWithRange:NSMakeRange(0, len - 1)]; } else { self.enteredDigits = @""; } } NSDecimalNumber *decimal = nil; if ( ![self.enteredDigits isEqualToString:@""]) { decimal = [[NSDecimalNumber decimalNumberWithString:self.enteredDigits] decimalNumberByMultiplyingByPowerOf10:currencyScale]; } else { decimal = [NSDecimalNumber zero]; } // Replace the text with the localized decimal number textField.text = [self.formatter stringFromNumber:decimal]; return NO; } 

Só testei isso com libras e centavos, mas também deveria funcionar com o iene japonês. Se você deseja formatar decimais para fins não monetários, leia a documentação no NSNumberFormatter e defina o formato / maximumFractionDigits desejado.

Uma implementação Swift 2 do post de Mike Weller, também apenas USD:

  func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { guard let str = textField.text else { textField.text = "0.00" return false } let value = (str as NSString).doubleValue var cents = round(value * 100) if string.characters.count > 0 { for c in string.characters { if let num = Int(String(c)) { cents *= 10 cents += Double(num) } } } else { cents = floor(cents / 10) } textField.text = NSString(format: "%.2f", cents/100) as String return false } 

Você pode usar STATextField e definir currencyRepresentation como YES, que:

Garante que não mais que um ponto decimal seja inserido e que não mais do que 2 dígitos sejam inseridos à direita do ponto decimal.

Há também STAATMTextField, que suporta o modo de moeda e input de texto ATM por padrão:

Fornece um campo de texto que imita o comportamento de input da máquina ATM.