Limit UITextField to a single decimal point of Swift

How can I limit a UITextField to one decimal point using Swift? The text box is for entering a price, so I cannot allow more than one decimal point. If I used Objective-C, I would use this code:

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string]; NSArray *sep = [newString componentsSeparatedByString:@"."]; if([sep count] >= 2) { NSString *sepStr=[NSString stringWithFormat:@"%@",[sep objectAtIndex:1]]; return !([sepStr length]>1); } return YES; } 

But due to differences in how Swift uses ranges, I cannot convert this code to Swift. The first line gives me an error saying NSRange is not convertible to Range<String.Index>

EDIT: I ended up doing this before I saw the answer:

 func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool { let tempRange = textField.text.rangeOfString(".", options: NSStringCompareOptions.LiteralSearch, range: nil, locale: nil) if tempRange?.isEmpty == false && string == "." { return false } return true } 

I found this in another post. This solution works fine, but I'm not sure if this is the best way to do this, but it is a short and clean way.

+2
ios objective-c uitextfield swift
source share
7 answers

Alexey got to me, but after seeing how I applied the Swift version to check the situation, here it is:

 func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool { // I'm explicitly unwrapping newString here, as I want to use reverse() on it, and that // apparently doesn't work with implicitly unwrapped Strings. if let newString = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string) { var decimalFound = false var charactersAfterDecimal = 0 for ch in reverse(newString) { if ch == "." { decimalFound = true break } charactersAfterDecimal++ } if decimalFound && charactersAfterDecimal > 1 { return false } } return true; } 

Note that the first line now explicitly passes textField.text to an NSString. This is because the String string stringByReplacingCharactersInRange accepts a Swift range, not an NSRange, like the one that passed.

I also made the later code much more Swiftian by removing NSString operations. (I'm not sure if this is wonderfully effective, since the inverse (String) can actually completely change the whole string, not just a simple inverse iterator, but it seems like the most Swifty way to do this.)

+4
source share

Your first line in Swift will look like this:

 var newString = NSString(string: textField.text).stringByReplacingCharactersInRange(range, withString: string) 
+1
source share

I suggest using the NSNumberFormatter decimalSeparator property to split your string. Here's how to limit input to one decimal only with NSNumberFormatter:

 func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { if string.isEmpty { // back key return true } if let input = textField.text { let numberFormatter = NSNumberFormatter() let range = input.rangeOfString(numberFormatter.decimalSeparator) if let r = range { let endIndex = input.startIndex.advancedBy(input.startIndex.distanceTo(r.endIndex)) let decimals = input.substringFromIndex(endIndex) return decimals.characters.count < 1 } } return true } 
+1
source share

func textField (textField: UITextField, shouldChangeCharactersInRange: NSRange, replacementString string: String) → Bool {if (textField.text? .componentsSeparatedByString ("."). count> 1 && string == ".") {return false} return string == "" || (string == "." || Float (string)! = nil)}

0
source share

Try this in one decimal notation: -

 func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { if(string == "." ){ let countdots = textField.text!.componentsSeparatedByString(".").count - 1 if countdots > 0 && string == "." { return false } } return true } 
0
source share

Swift 4 and Xcode 9.2

This solution allows you to enter only one decimal point, so double is acceptable.

 // Only allows one decimal point func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let newString = (textField.text! as NSString).replacingCharacters(in: range, with: string) let arrayOfString = newString.components(separatedBy: ".") if arrayOfString.count > 2 { return false } return true } 
0
source share

Hope this can help you:

 func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let newString = (textField.text! as NSString).replacingCharacters(in: range, with: string) let stringArr: [String] = newString.components(separatedBy: ".") if stringArr.count < 2 || (stringArr.count == 2 && stringArr[1].count == 1){ return true } return false } 
0
source share

All Articles