user5524779
user5524779

Reputation:

How to limit textfield decimal

How to limit the lenght of several UItextField in this way:

Max integer allowed two and max decimal allowed one.

I've used this code to limit the text to two number:

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {

var kMaxLength = 2
let oldString = textFieldlOne.text as NSString

let string = oldString.stringByReplacingCharactersInRange(range, withString: string)


return countElements(string) <= kMaxLength

 }

But I have several UITextfield IBOutlet and I want allow the user to insert one decimal number es. 12.5

Upvotes: 1

Views: 3928

Answers (5)

Dilip Jangid
Dilip Jangid

Reputation: 764

In swift 3, limit textfield's input value before and after decimal

let digitBeforeDecimal = 2
let digitAfterDecimal = 2
func textField(_ textField: UITextField, shouldChangeCharactersIn   range: NSRange, replacementString string: String) -> Bool {
    let computationString = (textField.text! as NSString).replacingCharacters(in: range, with: string)
    let arrayOfSubStrings = computationString.components(separatedBy: ".")
    if arrayOfSubStrings.count == 1 && computationString.count > digitBeforeDecimal {//
        return false
    } else if arrayOfSubStrings.count == 2 {
        let stringPostDecimal = arrayOfSubStrings[1]
        return stringPostDecimal.count <= digitAfterDecimal
    }
    return true
}

Upvotes: 0

SPatel
SPatel

Reputation: 4946

Swift 4

Using number formatter

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        let s = (textField.text ?? "").appending(string)
        let numberFormatter = NumberFormatter()
        numberFormatter.numberStyle = .decimal
        return numberFormatter.number(from: s)?.doubleValue != nil
    }

Upvotes: 0

Rob
Rob

Reputation: 437422

Regular expressions are useful when trying to test to see if a string matches a particular template:

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let oldString = textField.text ?? "" as NSString
    let candidate = oldString.stringByReplacingCharactersInRange(range, withString: string)
    let regex = try? NSRegularExpression(pattern: "^\\d{0,2}(\\.\\d?)?$", options: [])
    return regex?.firstMatchInString(candidate, options: [], range: NSRange(location: 0, length: candidate.characters.count)) != nil
}

The \d{0,2} matches zero to two digits. The (\.\d?)? translates to "if there is a decimal point, allow it and optionally one more digit." (You could also do (\.\d{0,1})?, too.) The ^ matches the "start of the string" and the $ matches the "end of the string" (i.e., we'll only find matches where the \d{0,2}(\.\d?)? is the entire string, and not just something that shows up in the middle of the string.) And, of course, all of those \ characters are escaped to be \\ in the string literal.

Regular expressions (regex) can be a little "dense" when you first encounter them, but once you gain familiarity with the syntax, it's an incredibly powerful tool.

--

By the way, I notice that you said in a comment that you're using Swift 1.1. I believe the equivalent Swift 1.1 syntax would be something like:

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
    let oldString = textField.text as NSString
    let candidate = oldString.stringByReplacingCharactersInRange(range, withString: string)
    var error: NSError?
    let regex = NSRegularExpression(pattern: "^\\d{0,2}(\\.\\d?)?$", options: 0, error: &error)
    return regex?.firstMatchInString(candidate, options: 0, range: NSRange(location: 0, length: candidate.length)) != nil
}

I don't have a Swift 1.1 compiler readily available, so I can't easily test/confirm this Swift 1.1 syntax, but if I recall correctly, it's something like that. Personally I'd recommend upgrading to the latest version of Xcode, but to each his own.

Upvotes: 5

Andr&#233; Slotta
Andr&#233; Slotta

Reputation: 14030

here is a swift conversion from @Vijayts answer:

struct Constants {
  static let MAX_BEFORE_DECIMAL_DIGITS = 2
  static let MAX_AFTER_DECIMAL_DIGITS = 1
}

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
  let computationString = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)

  // Take number of digits present after the decimal point.
  let arrayOfSubStrings = computationString.componentsSeparatedByString(".")

  if arrayOfSubStrings.count == 1 && computationString.characters.count > Constants.MAX_BEFORE_DECIMAL_DIGITS {
    return false
  } else if arrayOfSubStrings.count == 2 {
    let stringPostDecimal = arrayOfSubStrings[1]
    return stringPostDecimal.characters.count <= Constants.MAX_AFTER_DECIMAL_DIGITS
  }

  return true
}

Upvotes: 1

Vijay Tholpadi
Vijay Tholpadi

Reputation: 2295

I am not so adept with swift at this point in time. So I will try to solve it in Obj-C first.

#define MAX_BEFORE_DECIMAL_DIGITS = 2
#define MAX_AFTER_DECIMAL_DIGITS = 1

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range  replacementString:(NSString *)string {

NSString *computationString = [textField.text stringByReplacingCharactersInRange:range withString:string];

// Take number of digits present after the decimal point.
NSArray  *arrayOfSubStrings = [newString componentsSeparatedByString:@"."];

if(([arrayOfSubStrings count] == 1) && (computationString.length > MAX_BEFORE_DECIMAL_DIGITS)) {
    return NO;
} else if([arrayOfSubStrings count] == 2) {
    NSString *stringPostDecimal = [NSString stringWithFormat:@"%@",[arrayOfSubStrings objectAtIndex:1]];
    return !([stringPostDecimal length] > MAX_AFTER_DECIMAL_DIGITS);
}

return YES;
}

Define the value of MAX_BEFORE_DECIMAL_DIGITS and MAX_AFTER_DECIMAL_DIGITS as per your requirement.

Upvotes: 0

Related Questions