How to limit decimal input value in UITextField - ios

I am currently checking my UITextField, which is set to show Numeric Keypad in shouldChangeCharactersIn to limit the input to only one decimal separator and only 2 decimal points like this (thanks to this question):
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let decimalSeparator = String(Locale.current.decimalSeparator ?? ".")
if (textField.text?.contains(decimalSeparator))! {
let limitDecimalPlace = 2
let decimalPlace = textField.text?.components(separatedBy: decimalSeparator).last
if (decimalPlace?.count)! < limitDecimalPlace {
return true
} else {
return false
}
}
}
This works great. However, it is now possible to insert whatever value the user wants, which I want to limit to a value lower than 999. I used to check the length to allow only 3 characters, but now I want to allow following values (for example):
143
542.25
283.02
19.22
847.25
But I don't want to allow:
2222
3841.11
999.99
How could I do that?

You probably need two checks:
Make sure it in the form of xxx.xx. This sort of pattern matching is often achieved by using regular expression search.
The trick here is to make sure you support all permutations with and without decimal place, where the fractional digits is two or fewer digits and the integer digits is three or fewer digits.
Try converting it to a number and check that the value is less than 999.
Thus:
let formatter = NumberFormatter()
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let candidate = ((textField.text ?? "") as NSString).replacingCharacters(in: range, with: string)
let separator = formatter.decimalSeparator!
if candidate == "" { return true }
let isWellFormatted = candidate.range(of: "^[0-9]{1,3}([\(separator)][0-9]{0,2})?$", options: .regularExpression) != nil
if isWellFormatted,
let value = formatter.number(from: candidate)?.doubleValue,
value >= 0,
value < 999 {
return true
}
return false
}
Note:
I’m assuming you want users to be able to honor their device’s localization settings (e.g. let a German user enter 123,45 because they use , as the decimal separator).
The regular expression, "^[0-9]{1,3}([\(separator)][0-9]{0,2})?$” probably looks a little hairy if you’re not used to regex.
The ^ matches the start of the string;
The [0-9] obviously matches any digit;
The {1,3} matches between one and three integer digits;
The (...)? says “optionally, look for the following”;
Again, [0-9]{0,2} means “between zero and two fractional digits; and
The $ matches the end of the string.

Related

How to put TextField`s content type for Float on XCode?

I've a TextField to user put a number value (Float or Double), but in most of cases it number is Integer, but I must show the value in Float format for example: 3.0, 2.5. When the user put a Integer, the value shows like: 2. How I set a way to TextField automatically put in decimal point value?
ps. In the options of content type not have a option to number.
This is the wrong way:
There is no inbox solution, you should do it manually with UITextFieldDelegate:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
//customize your string here
}

Swift - How can I force users to import only integer in UITextField?

Normally, in Text Field, users can enter a String, and even if the users entered a number, the program would automatically understand it as a string.
So, here is my problem. I want to make a program evaluating the speed of a motorcyclist.
I have a text field, a text view and a button START. What I want to do is to apply SWITCH - CASE in classifying the number that the users enter in the text field, and then I will print out my evaluations to the text view, such as "Slow", "Fast Enough" or "Dangerously Fast".
However before applying switch - case, I think that I have to force the users to only enter Integer numbers to the text field. And if they enter any alphabet letter, the text view will appear: "Wrong format! Please try again!"
I think that I have to do something with the statement if to solve the problem, but the truth is I've just started learning Swift, and couldnt think of any possible solutions. Please help me.
Thank you.
If you are using storyboard just select the TextField and change the Keyboard type to NumberPad. This will only allow integers to be entered. Then you could just turn it into a Int when you get back the input.
if let convertedSpeed = Int(textField.text) {
// Implement whatever you want
} else {
// Notify user of incorrect input
}
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
if textField == Number_Txt // your text filed name
{
var result = true
let prospectiveText = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)
if string.characters.count > 0
{
let disallowedCharacterSet = NSCharacterSet(charactersInString: "0123456789").invertedSet
let replacementStringIsLegal = string.rangeOfCharacterFromSet(disallowedCharacterSet) == nil
let resultingStringLengthIsLegal = prospectiveText.characters.count > 0
let scanner = NSScanner(string: prospectiveText)
let resultingTextIsNumeric = scanner.scanDecimal(nil) && scanner.atEnd
result = replacementStringIsLegal && resultingStringLengthIsLegal && resultingTextIsNumeric
}
return result
}
else
{
return true
}
}
You can solve it in two ways.
Convert the typed text to Integer value.
Int(textfield.text!)
This one is very simpler. Choose the keyboard type as Numeric/ Numbers and Punctuation pad. So that, user can type only the nos.
Hope it helps..
You can specify the keyboard type of a textfield in storyboard, under attributes inspector.
"Decimal" would be the way to go for you (assuming that possible input can be e.g. 180.5)
To move on, you still can check the input like this:
if (Int(textfield.text!) != nil ) {
//Valid number, do stuff
} else {
textfield.text = "Wrong format! Please try again!"
}
EDIT:
The ' != nil ' means the following:
The Initializer of Int is failable. That means if you pass a string which does not contain a valid number, it will return nil (null if you are coming from java/c#). But if the string does contain a valid number, it will return a valid Int, therefore its not nil. I hope this makes it clear to you ;)

Test UITextField text string to only contain alphanumeric characters

Im trying to complete form validation in Swift and cant find a way of testing for only Alphanumeric characters in a UITextField.text.
Ive found NSCharacterSet to help test if at least 1 letter has been entered (so far):
#IBOutlet weak var username: UITextField!
let letters = NSCharacterSet.letterCharacterSet()
//Check username contains a letter
if (username.text!.rangeOfCharacterFromSet(letters) == nil) {
getAlert("Error", message: "Username must contain at least 1 letter")
}
Now i just need a way to validate that only numbers, letters (maybe even underscores and dashes) to be entered. Loads of stuff out there for Obj-C but I need a SWIFT solution please.
Thank you in advance.
Check if the inversion of your accepted set is present:
if username.text!.rangeOfCharacterFromSet(letters.invertedSet) != nil {
print("invalid")
}
letters should probably be alphanumericCharacterSet() if you want to include numbers as well.
If you want to accept underscores or more chars, you will probably have to create a character set by your own. But the inversion logic will stay the same.
Though it's late to answer, but this answer might be useful to someone.
This is simple and worked like a charm for me.
Swift 3:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
/// 1. replacementString is NOT empty means we are entering text or pasting text: perform the logic
/// 2. replacementString is empty means we are deleting text: return true
if string.characters.count > 0 {
var allowedCharacters = CharacterSet.alphanumerics
/// add characters which we need to be allowed
allowedCharacters.insert(charactersIn: " -") // "white space & hyphen"
let unwantedStr = string.trimmingCharacters(in: allowedCharacters)
return unwantedStr.characters.count == 0
}
return true
}
Note: This will work for pasting strings into the text field as well. Pasted string will not be displayed in text field if it contains any unwanted characters.

How do I check if the user has entered more than 1 decimal in a text field?

I created a tipCalculator app but if the user enters a number with multiple decimal points, the app crashes. How do I go about fixing this?
One simple way would be just testing the amount of decimals in the text string, and if there are more than 1, alert the user.
NSUInteger numOfDecimals = [[yourTextField.text componentsSeparatedByString:#"."] count] - 1;
if(numOfDecimals > 1)
{
// do something
}
I would suggest stopping the user from entering more than one decimal point.
Add UITextFieldDelegate to your class declaration.
In your viewDidLoad method add the following line:
yourTextField.delegate = self
Finally add the following method to your class:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
return textField.text?.componentsSeparatedByString(".").count <= 2
}

Swift - Maintaining decimal point with Editing Changed

I am creating a unit converter and want all the units to update simultaneously as the user enters a value. e.g. entering 25 into the 'cm' field will automatically display 250 in the 'mm' field and 0.25 in the 'metre' field.
This is so far working great using Editing Changed event so long as the user enters whole numbers, as soon as a decimal is entered iOS automatically strips the decimal away to format the UITextField as a whole number since it is formatting after each keypress and assumes the the number entered ends with a decimal point i.e "25." which then becomes "25" instead of "25.0".
For instance entering 25.6 will display as 256.
Is there any way to prevent this automatic formatting? The only solution I have found is to link the event to Editing Did End but this is not ideal as the other units will only become updated after the user finishes entering the value and not updated automatically as I require.
The code I'm using to convert from string to double is as follows:
#IBAction func editMm(sender: AnyObject) {
var setToDouble:Double? = stringToDouble(textFieldMm.text)
valueEdited(setToBase!)
}
func stringToDouble(inputString:String) -> Double{
// this removes the comma separators which are automatically added to the UITextField during formatting
var formattedString = inputString.stringByReplacingOccurrencesOfString(",", withString: "")
var doubleResult:Double = (formattedString as NSString).doubleValue
return doubleResult
}
I've tried to catch this in the stringToDouble function but it seems the formatting happens before the value reaches that point in the code.
You can use the shouldChangeCharactersInRange function in UITextFieldDelegate. The newString will contain the current string while editing.
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let newString = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
println(newString)
return true
}

Resources