iphone - redondear - reglas de redondeo de numeros decimales
¿Cuál es la mejor manera de ingresar valores numéricos con puntos decimales? (11)
En mi aplicación, los usuarios deben poder ingresar valores numéricos con decimales. El iPhone no proporciona un teclado específico para este propósito, solo un teclado numérico y un teclado con números y símbolos.
¿Existe una manera fácil de utilizar este último y evitar que se ingrese cualquier entrada no numérica sin tener que volver a expresar el resultado final?
¡Gracias!
A partir de iOS4.1, hay un nuevo tipo de teclado UIKeyboardTypeNumberPad, pero desafortunadamente, hasta el momento no parece aparecer en la lista de selección de Interface Builder.
Aquí hay un ejemplo de la solución sugerida en la respuesta aceptada. Esto no maneja otras monedas ni nada, en mi caso solo necesitaba soporte para dólares, sin importar la configuración regional / moneda, así que esto estaba bien para mí:
-(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;
}
Las rondas y los niveles son importantes a) debido a la representación en coma flotante que a veces pierde .00001 o lo que sea, yb) la cadena de formato redondea cualquier precisión que eliminamos en la parte de retroceso.
Aquí se explica cómo hacerlo sin usar flotantes, round () o ceil () de una manera independiente de la divisa.
En su controlador de vista, configure las siguientes variables de instancia (con declaraciones @property asociadas si esa es su cartera):
@interface MyViewController : UIViewController <UITextFieldDelegate> {
@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
y su método viewDidLoad debe contener lo siguiente:
- (void)viewDidLoad {
[super viewDidLoad];
NSNumberFormatter *aFormatter = [[NSNumberFormatter alloc] init];
[aFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
currencyScale = -1 * [aFormatter maximumFractionDigits];
self.formatter = aFormatter;
[aFormatter release];
}
A continuación, implemente sus métodos UITextFieldDelegate de la siguiente manera:
#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;
}
Solo probé esto con libras y peniques, pero también debería funcionar con yenes japoneses. Si desea formatear decimales para fines no monetarios, simplemente lea la documentación en NSNumberFormatter y establezca el formato / maximumFractionDigits que desee.
Creé un controlador numérico personalizado de vista de pad con punto decimal ... compruébalo:
http://sites.google.com/site/psychopupnet/iphone-sdk/tenkeypadcustom10-keypadwithdecimal
Creo que sería bueno señalar que a partir de iOS 4.1 puedes usar el nuevo UIKeyboardTypeDecimalPad
.
Entonces ahora solo tienes que:
myTextField.keyboardType=UIKeyboardTypeDecimalPad;
Dependiendo de la aplicación específica, proporcionar un control deslizante para que el usuario pueda seleccionar una posición podría ser una mejor opción en el iPhone. Entonces no es necesario ingresar ningún dígito.
Es posible que desee utilizar un control deslizante (como lo sugiere Martin v. Löwis) o un UIPickerView con una rueda separada para cada uno de los dígitos.
Puede usar STATextField y establecer currencyRepresentation en YES que:
Asegura que no se ingrese más de un punto decimal y que no se ingresen más de 2 dígitos a la derecha de dicho punto decimal.
También hay STAATMTextField que admite el modo de moneda y la entrada de texto ATM de forma predeterminada:
Proporciona un campo de texto que imita el comportamiento de entrada de la máquina ATM.
Quería hacer exactamente lo mismo, excepto con monedas en lugar de valores decimales rectos.
Terminé creando una vista personalizada que contiene un UITextField y un UILabel. La etiqueta cubre el campo de texto, pero el campo de texto aún recibe toques. Utilizo la notificación UITextFieldTextDidChange para observar los cambios en el campo de texto (y utilicé NSNumberFormatter para convertir el número resultante en un valor de moneda formateado) para actualizar la etiqueta.
Para desactivar la lupa que permite al usuario cambiar la posición del punto de inserción, deberá usar una subclase UITextField personalizada y anular touchesBegan: withEvent: y configurarla para que no haga nada.
Mi solución puede ser diferente de la que necesita porque el punto decimal siempre está fijo: utilizo la configuración de moneda del sistema para determinar cuántos dígitos debe tener después del punto decimal. Sin embargo, el teclado numérico no tiene un punto decimal. Y no puede agregar ningún botón al teclado (¡lo que es especialmente molesto porque hay un botón en blanco en la esquina inferior izquierda del teclado que sería perfecto para un punto decimal!) Así que no tengo una solución para eso , Desafortunadamente.
Una implementación Swift 2 de la publicación de Mike Weller, también solo 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
}
Una solución más elegante pasa a ser también la más simple.
No necesita una clave de separación decimal
¿Por qué? Porque simplemente puede inferirlo de la entrada del usuario. Por ejemplo, en la configuración regional de EE. UU. Cuando ingresa $ 1.23, comienza ingresando los números 1-2-3 (en ese orden). En el sistema, a medida que se ingresa cada carácter, esto se reconocería como:
- el usuario ingresa 1: $ 0.01
- el usuario ingresa 2: $ 0.12
- el usuario ingresa 3: $ 1.23
Observe cómo deducimos el separador decimal basado en la entrada del usuario. Ahora, si el usuario quiere ingresar $ 1.00, simplemente ingresaría los números 1-0-0.
Para que su código maneje monedas de una configuración regional diferente, necesita obtener los dígitos de fracción máxima de la moneda. Esto se puede hacer con el siguiente fragmento de código:
NSNumberFormatter *currencyFormatter = [[NSNumberFormatter alloc] init];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
int currencyScale = [currencyFormatter maximumFractionDigits];
Por ejemplo, el yen japonés tiene un dígito de fracción máxima de 0. Por lo tanto, cuando se trata de la entrada de yenes, no hay separador decimal y, por lo tanto, no hay necesidad de preocuparse por las cantidades fraccionarias.
Este enfoque al problema le permite utilizar el teclado de entrada de valores numéricos provisto por Apple sin los dolores de cabeza de los teclados personalizados, la validación de expresiones regulares, etc.