ios - ¿Cómo puedo limitar el número de puntos decimales en un UITextField?
decimal-point (13)
Tengo un UITextField que, al hacer clic, muestra un teclado numérico con un punto decimal en la parte inferior izquierda. Estoy tratando de limitar el campo para que un usuario solo pueda colocar una marca decimal
p.ej
2.5 ok
2..5 NO OK
Swift 4
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// Allow to remove character (Backspace)
if string == "" {
return true
}
// Block multiple dot
if (textField.text?.contains("."))! && string == "." {
return false
}
// Check here decimal places
if (textField.text?.contains("."))! {
let limitDecimalPlace = 2
let decimalPlace = textField.text?.components(separatedBy: ".").last
if (decimalPlace?.count)! < limitDecimalPlace {
return true
}
else {
return false
}
}
return true
}
C objetivo
//Create this variable in .h file or .m file
float _numberOfDecimal;
//assign value in viewDidLoad method
numberOfDecimal = 2;
#pragma mark - TextFieldDelegate
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
// Allow to remove character (Backspace)
if ([string isEqualToString:@""]) {
return true;
}
// Block multiple dot
if ([textField.text containsString:@"."] && [string isEqualToString:@"."]) {
return false;
}
// Check here decimal places
if ([textField.text containsString:@"."]) {
NSString *strDecimalPlace = [[textField.text componentsSeparatedByString:@"."] lastObject];
if (strDecimalPlace.length < _numberOfDecimal) {
return true;
}
else {
return false;
}
}
return true;
}
Aquí hay un ejemplo con una expresión regular, el ejemplo se limita a solo un punto decimal y 2 decimales. Puedes modificarlo para que se ajuste a tus necesidades.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSString *expression = @"^[0-9]*((//.|,)[0-9]{0,2})?$";
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:expression options:NSRegularExpressionCaseInsensitive error:&error];
NSUInteger numberOfMatches = [regex numberOfMatchesInString:newString options:0 range:NSMakeRange(0, [newString length])];
return numberOfMatches != 0;
}
En cualquier objeto que configure el delegado de su UITextField, agregue un método que responda a " [- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string]
" .
Luego puede usar un objeto NSNumberFormatter
o puede controlar la fuerza bruta para una marca de posición decimal ya existente (devolviendo NO
si ya existe una marca decimal).
Hice la solución que le brinda control sobre el recuento de lugares decimales, de modo que el usuario solo puede escribir un separador decimal y también puede tener un control sobre el recuento de lugares decimales.
Solo establece el valor decimalPlacesLimit correctamente.
Vea el método:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSLog(@"text on the way: %@", string);
NSUInteger decimalPlacesLimit = 2;
NSRange rangeDot = [textField.text rangeOfString:@"." options:NSCaseInsensitiveSearch];
NSRange rangeComma = [textField.text rangeOfString:@"," options:NSCaseInsensitiveSearch];
if (rangeDot.length > 0 || rangeComma.length > 0){
if([string isEqualToString:@"."]) {
NSLog(@"textField already contains a separator");
return NO;
} else {
NSArray *explodedString = [textField.text componentsSeparatedByString:@"."];
NSString *decimalPart = explodedString[1];
if (decimalPart.length >= decimalPlacesLimit && ![string isEqualToString:@""]) {
NSLog(@"textField already contains %d decimal places", decimalPlacesLimit);
return NO;
}
}
}
return YES;
}
Implementar el método shouldChangeCharactersInRange de esta manera:
// Only allow one decimal point
// Example assumes ARC - Implement proper memory management if not using.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSArray *arrayOfString = [newString componentsSeparatedByString:@"."];
if ([arrayOfString count] > 2 )
return NO;
return YES;
}
Esto crea una matriz de cadenas divididas por el punto decimal, por lo que si hay más de un punto decimal tendremos al menos 3 elementos en la matriz.
Prueba esto :-
public func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
if(text == "," || text == "." ){
let countdots = textView.text!.componentsSeparatedByString(".").count - 1
if countdots > 0 && (text == "." || text == "," )
{
return false
}
}
return true
}
Sobre la base de la respuesta aceptada, el siguiente enfoque valida tres casos que son útiles cuando se trata de formatos de dinero:
- Cantidades extremadamente grandes
- Más de 2 caracteres después del punto decimal.
- Más de 1 punto decimal
Asegúrese de que el delegado de su campo de texto esté configurado correctamente, su clase cumpla con el protocolo UITextField
y agregue el siguiente método de delegado.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
// Check for deletion of the $ sign
if (range.location == 0 && [textField.text hasPrefix:@"$"])
return NO;
NSString *updatedText = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSArray *stringsArray = [updatedText componentsSeparatedByString:@"."];
// Check for an absurdly large amount
if (stringsArray.count > 0)
{
NSString *dollarAmount = stringsArray[0];
if (dollarAmount.length > 6)
return NO;
}
// Check for more than 2 chars after the decimal point
if (stringsArray.count > 1)
{
NSString *centAmount = stringsArray[1];
if (centAmount.length > 2)
return NO;
}
// Check for a second decimal point
if (stringsArray.count > 2)
return NO;
return YES;
}
Swift 3 Implemente este método UITextFieldDelegate para evitar que el usuario escriba un número no válido:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let text = (textField.text ?? "") as NSString
let newText = text.replacingCharacters(in: range, with: string)
if let regex = try? NSRegularExpression(pattern: "^[0-9]*((//.|,)[0-9]*)?$", options: .caseInsensitive) {
return regex.numberOfMatches(in: newText, options: .reportProgress, range: NSRange(location: 0, length: (newText as NSString).length)) > 0
}
return false
}
Está trabajando con coma o punto como separador decimal. También puede limitar el número de dígitos de fracciones usando este patrón: "^[0-9]*((//.|,)[0-9]{0,2})?$"
(En este caso 2).
[NSString stringWithFormat:@"%9.5f", x];
, el formato del número es el siguiente [NSString stringWithFormat:@"%9.5f", x];
Donde 5 es el decimal después de ",".
Para Swift 2.3 para evitar que el usuario ingrese el número decimal después de dos lugares -
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
let decimalPlacesLimit = 2
let rangeDot = txtPrice.text!.rangeOfString(".", options: .CaseInsensitiveSearch)
if rangeDot?.count > 0
{
if (string == ".")
{
print("textField already contains a separator")
return false
}
else {
var explodedString = txtPrice.text!.componentsSeparatedByString(".")
let decimalPart = explodedString[1]
if decimalPart.characters.count >= decimalPlacesLimit && !(string == "")
{
print("textField already contains /(decimalPlacesLimit) decimal places")
return false
}
}
}
}
Swift 3
No es necesario crear una matriz y comprobar el recuento. El usuario límite solo puede colocar 1 marca decimal como esta.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if (textField.text?.contains("."))! && string.contains(".")
{
return false
}
else
{
return true
}
}
Swift 4
La forma eficiente y fácil de evitar múltiples puntos decimales (. O,) en UITextField:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if(string == "," || string == "." ){
if ((textField.text?.contains(","))! || (textField.text?.contains("."))!){
return false
}
}
return true
}
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if(textField == min_textfield )
{
if([textField.text rangeOfString:@"."].location == NSNotFound)
{
if([string isEqualToString:@"."] )
{
flag_for_text = 1;
}
else
{
textField.text = [NSMutableString stringWithFormat:@"%@",textField.text];
}
}
else
{
if([string isEqualToString:@"."])
{
return NO;
}
else
{
textField.text = [NSMutableString stringWithFormat:@"%@",textField.text];
}
}
}
}