UITextField Should accept number only values - ios

I have UITexfields i want that it should accept only number other shows alert that enter a numeric value.
I want that motionSicknessTextFiled should only accept number
NSString*dogswithMotionSickness=motionSicknessTextField.text;
NSString*valueOne=cereniaTextField.text;
NSString*valueTwo=prescriptionTextField.text;
NSString*valueThree=otherMeansTextField.text;
NSString*valueFour=overtheCounterTextField.text;

In whatever UITextField you're getting these values from, you can specify the kind of keyboard you want to appear when somebody touches inside the text field.
E.G. a numeric-only keyboard.
Like this screenshot:
This is easily set when working with the XIB and the Interface Builder built into Xcode, but if you want to understand this programmatically, take a look at Apple's UITextInputTraits protocol reference page, specifically the keyboardType property information.
To filter out punctuations, set the textfield's delegate and set up the shouldChangeCharactersInRange method:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    NSCharacterSet *numbersOnly = [NSCharacterSet characterSetWithCharactersInString:#"0123456789"];
NSCharacterSet *characterSetFromTextField = [NSCharacterSet characterSetWithCharactersInString:textField.text];
    BOOL stringIsValid = [numbersOnly isSupersetOfSet:characterSetFromTextField];
    return stringIsValid;
}

Objective C
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (!string.length)
return YES;
if (textField == self.tmpTextField)
{
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSString *expression = #"^([0-9]+)?(\\.([0-9]{1,2})?)?$";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:expression
options:NSRegularExpressionCaseInsensitive
error:nil];
NSUInteger numberOfMatches = [regex numberOfMatchesInString:newString
options:0
range:NSMakeRange(0, [newString length])];
if (numberOfMatches == 0)
return NO;
}
return YES;
}
Swift 3.0
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if !string.characters.count {
return true
}
do {
if textField == self.tmpTextField {
var newString = textField.text.replacingCharacters(inRange: range, with: string)
var expression = "^([0-9]+)?(\\.([0-9]{1,2})?)?$"
var regex = try NSRegularExpression(pattern: expression, options: NSRegularExpressionCaseInsensitive)
var numberOfMatches = regex.numberOfMatches(inString: newString, options: [], range: NSRange(location: 0, length: newString.characters.count))
if numberOfMatches == 0 {
return false
}
}
}
catch let error {
}
return true
}

[textField setKeyboardType:UIKeyboardTypeNumberPad];

I've implemented the snippet which has the features for textField:
Check the maximum allowed characters.
Check the valid decimal number.
Check only numeric numbers.
The code is the UITextField delegate method. Before you use this snippet, you must have these properties:
self.maxCharacters
self.numeric // Only int characters.
self.decimalNumeric // Only numbers and ".", "," (for specific locales, like Russian).
Code:
- (BOOL)textField:(UITextField *) textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if(self.numeric || self.decimalNumeric)
{
NSString *fulltext = [textField.text stringByAppendingString:string];
NSString *charactersSetString = #"0123456789";
// For decimal keyboard, allow "dot" and "comma" characters.
if(self.decimalNumeric) {
charactersSetString = [charactersSetString stringByAppendingString:#".,"];
}
NSCharacterSet *numbersOnly = [NSCharacterSet characterSetWithCharactersInString:charactersSetString];
NSCharacterSet *characterSetFromTextField = [NSCharacterSet characterSetWithCharactersInString:fulltext];
// If typed character is out of Set, ignore it.
BOOL stringIsValid = [numbersOnly isSupersetOfSet:characterSetFromTextField];
if(!stringIsValid) {
return NO;
}
if(self.decimalNumeric)
{
NSString *currentText = [textField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
// Change the "," (appears in other locale keyboards, such as russian) key ot "."
currentText = [currentText stringByReplacingOccurrencesOfString:#"," withString:#"."];
// Check the statements of decimal value.
if([fulltext isEqualToString:#"."]) {
textField.text = #"0.";
return NO;
}
if([fulltext rangeOfString:#".."].location != NSNotFound) {
textField.text = [fulltext stringByReplacingOccurrencesOfString:#".." withString:#"."];
return NO;
}
// If second dot is typed, ignore it.
NSArray *dots = [fulltext componentsSeparatedByString:#"."];
if(dots.count > 2) {
textField.text = currentText;
return NO;
}
// If first character is zero and second character is > 0, replace first with second. 05 => 5;
if(fulltext.length == 2) {
if([[fulltext substringToIndex:1] isEqualToString:#"0"] && ![fulltext isEqualToString:#"0."]) {
textField.text = [fulltext substringWithRange:NSMakeRange(1, 1)];
return NO;
}
}
}
}
// Check the max characters typed.
NSUInteger oldLength = [textField.text length];
NSUInteger replacementLength = [string length];
NSUInteger rangeLength = range.length;
NSUInteger newLength = oldLength - rangeLength + replacementLength;
BOOL returnKey = [string rangeOfString: #"\n"].location != NSNotFound;
return newLength <= _maxCharacters || returnKey;
}
Demo:

Modified Michael Dautermann's answer:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if(string.length > 0)
{
NSCharacterSet *numbersOnly = [NSCharacterSet characterSetWithCharactersInString:#"0123456789"];
NSCharacterSet *characterSetFromTextField = [NSCharacterSet characterSetWithCharactersInString:string];
BOOL stringIsValid = [numbersOnly isSupersetOfSet:characterSetFromTextField];
return stringIsValid;
}
return YES;
}

swift 4
This allows only number input and you can also set character limitation
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let aSet = NSCharacterSet(charactersIn:"0123456789").inverted
let compSepByCharInSet = string.components(separatedBy: aSet)
let numberFiltered = compSepByCharInSet.joined(separator: "")
if string == numberFiltered {
let currentText = textField.text ?? ""
guard let stringRange = Range(range, in: currentText) else { return false }
let updatedText = currentText.replacingCharacters(in: stringRange, with: string)
return updatedText.count <= 10
} else {
return false
}
}

Here is Swift solution:
In viewDidLoad set the delegate:
_yourTextField.delegate = self
let _acceptableCharacters = "0123456789."
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if (string.characters.count == 0) {
return true
}
if (textField == self._yourTextField) {
let cs = NSCharacterSet(charactersInString: self._acceptableCharacters)
let filtered = string.componentsSeparatedByCharactersInSet(cs).filter { !$0.isEmpty }
let str = filtered.joinWithSeparator("")
return (string != str)
}
return true
}

this is the function which checks for the String contains Numeric value only
+(BOOL) checkforNumeric:(NSString*) str
{
NSString *strMatchstring=#"\\b([0-9%_.+\\-]+)\\b";
NSPredicate *textpredicate=[NSPredicate predicateWithFormat:#"SELF MATCHES %#", strMatchstring];
if(![textpredicate evaluateWithObject:str])
{
//////NSLog(#"Invalid email address found");
UIAlertView *objAlert = [[UIAlertView alloc] initWithTitle:APP_NAME message:#"please enter valid text." delegate:nil cancelButtonTitle:nil otherButtonTitles:#"Close",nil];
[objAlert show];
[objAlert release];
return FALSE;
}
return TRUE;
}
check it on submit button.

This answer threw some error in Swift 3, here's the working answer:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if string.characters.count == 0 {
return true
}
do {
if textField == self.numberTextField {
let nString = textField.text as NSString?
let newString = nString?.replacingCharacters(in: range, with: string)
let expression = "^([0-9]+)?(\\.([0-9]{1,2})?)?$"
let regex = try NSRegularExpression(pattern: expression, options: .caseInsensitive)
let numberOfMatches = regex.numberOfMatches(in: newString! as String, options: [], range: NSRange(location: 0, length: (newString?.characters.count)!))
if numberOfMatches == 0 {
return false
}
}
}
catch let error {
}
return true
}

I just modified the answer of Michael and made it a little bit easier to implement. Just make sure that the delegate of your UITextfield is set to itself.
yourTxtField.delegate = self;
Furthermore copy & paste this code into your main file.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (textField == yourTxtField) {
NSCharacterSet *numbersOnly = [NSCharacterSet characterSetWithCharactersInString:#"0123456789"];
NSCharacterSet *characterSetFromTextField = [NSCharacterSet characterSetWithCharactersInString:string];
BOOL stringIsValid = [numbersOnly isSupersetOfSet:characterSetFromTextField];
return stringIsValid;
}else {
return YES;
}
}
If you want to allow the use of the spacebar just put in a blank space at the end of the CharactersInString, just like so:
#"0123456789" -> #"0123456789 "
Additionally:
If you want to restrict the length of the string just replace the if-function with following:
if (textField == yourTxtField) {
NSUInteger newLength = [textField.text length] + [string length] - range.length;
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:#"1234567890"] invertedSet];
NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:#""];
return (([string isEqualToString:filtered])&&(newLength <= 10));
}
In my case the "10" at the end represents the limit of characters.
Cheers! :)

Swift 4.2 port of the best answer here by #almas-adlibek
A bunch of configuration variables:
private let kMaxTextLength = 8
private let kZeroDotted = "0."
private let kZero = "0"
private let kDoubleDot = ".."
private let kDot = "."
private let kPeriod = ","
Now the Swift 4 converted part of the code.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
guard let oldText = textField.text, let swiftRange = Range(range, in: oldText) else {
return true
}
let newText = oldText.replacingCharacters(in: swiftRange, with: string)
var currentText = textField.text?.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
// Change the "," (appears in other locale keyboards, such as russian) key ot "."
currentText = currentText?.replacingOccurrences(of: kPeriod, with: kDot)
// Check the statements of decimal value.
if (newText == kDot) {
textField.text = kZeroDotted;
return false
}
if (newText.range(of: kDoubleDot) != nil) {
textField.text = newText.replacingOccurrences(of: kDoubleDot, with: kDot);
return false
}
// If second dot is typed, ignore it.
let dots = newText.components(separatedBy: kDot)
if(dots.count > 2) {
textField.text = currentText;
return false
}
// If first character is zero and second character is > 0, replace first with second. 05 => 5;
if(newText.count == 2) {
if(newText[0...0] == kZero && newText != kZeroDotted) {
textField.text = newText[1...1]
return false
}
}
// Check the max characters typed.
let oldLength = textField.text?.count ?? 0
let replacementLength = string.count
let rangeLength = range.length
let newLength = oldLength - rangeLength + replacementLength;
let returnKey = string.rangeOfCharacter(from: CharacterSet.newlines) != nil
return newLength <= kMaxTextLength || returnKey;
}

Swift
class ExampleVC: UIViewController {
let numbers = "0123456789";
override func viewDidLoad() {
super.viewDidLoad()
let textfield = UITextField(frame: CGRectMake(20, 100, 300, 44))
//make some customization, if you want
self.view.addSubview(textfield)
textfield.delegate = self;
}
}
extension ExampleVC: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return string.characters.count > 0 ? numbers.contains(string) : true
}
}

Another option of entering only numeric values into your text field is by selecting the keyboard type attribute of the corresponding textfield. Attaching the screenshot for reference.

Here is the working example for swift 4
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
{
// Allow Backspace
if string.count == 0 {
return true
}
// Allow Only Valid Decimal Numbers
if let textFieldText = textField.text {
let finalText = (textFieldText as NSString).replacingCharacters(in: range, with: string)
if Double(finalText) != nil {
return true
}
}
return false
}

Related

How do I configure the text field to account for the expiry date?

I am entering credit card information and I want the expiry date to be a max of 5 characters 4 numbers and a "/" automatically enters after the first two characters i.e. 01/17 after typing 01 the / is automatically entered, and allows only two more characters "17".
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
if textField == expire{
}
return true
}
Swift 4 solution, based on #Jigar's answer:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if range.length > 0 {
return true
}
if string == "" {
return false
}
if range.location > 4 {
return false
}
var originalText = textField.text
let replacementText = string.replacingOccurrences(of: " ", with: "")
//Verify entered text is a numeric value
if !CharacterSet.decimalDigits.isSuperset(of: CharacterSet(charactersIn: replacementText)) {
return false
}
//Put / after 2 digit
if range.location == 2 {
originalText?.append("/")
textField.text = originalText
}
return true
}
Try like this, Its working at my end.
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
//Range.Lenth will greater than 0 if user is deleting text - Allow it to replce
if range.length > 0
{
if range.location == 3 {
var originalText = textField.text
originalText = originalText?.replacingOccurrences(of: "/", with: "")
textField.text = originalText
}
return true
}
//Dont allow empty strings
if string == " "
{
return false
}
//Check for max length including the spacers we added
if range.location >= 5
{
return false
}
var originalText = textField.text
let replacementText = string.stringByReplacingOccurrencesOfString(" ", withString: "")
//Verify entered text is a numeric value
let digits = NSCharacterSet.decimalDigitCharacterSet()
for char in replacementText.unicodeScalars
{
if !digits.longCharacterIsMember(char.value)
{
return false
}
}
//Put / space after 2 digit
if range.location == 2
{
originalText?.appendContentsOf("/")
textField.text = originalText
}
return true
}
Hope this help you.
The answers do not handle backspace really well. Here's my solution (implemented in Objective-C unfortunately):
#interface CreditCardViewController()
<UITextFieldDelegate>
#property (weak,nonatomic) IBOutlet UITextField * cardExpirationTextField;
#property (strong,nonatomic) NSString * previousExpiryDate;
#property (strong,nonatomic) UITextRange * previousExpiryDateSelection;
#property (assign,readonly,nonatomic) NSString * minYearLast2Digits;
#end
#implementation CreditCardViewController
-(instancetype) init
{
self = [super initWithNibName:NSStringFromClass([CreditCardViewController class]) bundle:nil];
if(self){
_minYearLast2Digits = [[[NSNumber numberWithInteger:[NSDate date].year] stringValue] substringFromIndex:2];
}
return self;
}
-(void) viewDidLoad
{
[super viewDidLoad];
[self setupView]
}
-(void) setupView
{
self.cardExpirationTextField.delegate = self;
[self.cardExpirationTextField addTarget:self
action:#selector(reformatCardExpiryDate:)
forControlEvents:UIControlEventEditingChanged];
}
-(BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSUInteger newLength = [textField.text length] + [string length] - range.length;
if(textField == self.cardExpirationTextField){
self.previousExpiryDate = textField.text;
self.previousExpiryDateSelection = textField.selectedTextRange;
return newLength <= 5;
}
return YES;
}
-(void) reformatCardExpiryDate:(UITextField*) textField
{
const BOOL isErasing = self.previousExpiryDate.length > textField.text.length;
BOOL invalid = [textField.text length] > 5;
if([textField.text length] > 0){
unichar firstChar = [textField.text characterAtIndex:0];
invalid |= (firstChar > '1');
}
if([textField.text length] > 1){
unichar firstChar = [textField.text characterAtIndex:0];
unichar secondChar = [textField.text characterAtIndex:1];
invalid |= (firstChar == '1' && secondChar > '2');
}
if([textField.text length] > 2){
invalid |= [textField.text characterAtIndex:2] != '/';
}
if([textField.text length] > 3){
unichar yearFirstDigit = [textField.text characterAtIndex:3];
unichar minYearFirstDigit = [self.minYearLast2Digits characterAtIndex:0];
invalid |= yearFirstDigit < minYearFirstDigit;
}
if([textField.text length] > 4){
NSString* yearLastTwoDigits = [textField.text substringFromIndex:3];
invalid |= [yearLastTwoDigits compare:_minYearLast2Digits] == NSOrderedAscending;
}
if(invalid){
[textField setText:self.previousExpiryDate];
textField.selectedTextRange = self.previousExpiryDateSelection;
return;
}
if(!isErasing && textField.text.length == 2){
textField.text = [textField.text stringByAppendingString:#"/"];
UITextPosition *targetPosition =
[textField positionFromPosition:[textField beginningOfDocument]
offset:textField.text.length];
[textField setSelectedTextRange:
[textField textRangeFromPosition:targetPosition
toPosition:targetPosition]
];
}
}
#end
try this code:
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
let num:NSString = textField.text! ;
if num.length == 1
{
textField.text = NSString(format:"%#%#/",num,string) as String
return false;
}
if num.length >= 5 {
// allows only two more characters "17".
return false;
}
return true;
}
i just coded this and it work fine for me.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
var index = range.lowerBound
let fecha = textField.text!
if string == "" {
var array = Array(fecha)
array.remove(at: index)
if array.count > 2 {
if !array.contains("/"){
array.insert("/", at: 2)
}
}
textField.text = String(array)
let cursorPosition = textField.position(from: textField.beginningOfDocument, offset: index)!
textField.selectedTextRange = textField.textRange(from: cursorPosition, to: cursorPosition)
}else{
let expiracion = fecha.replacingOccurrences(of: "/", with: "")
if fecha != expiracion{
if index > 1 {
index = range.lowerBound - 1
}
}
var array = Array(expiracion)
if array.count < 4 {
print("index: \(index) - \(array)")
let newChar = Character(string)
array.insert(newChar, at: index)
print("new array: ", array)
if array.count > 2 {
array.insert("/", at: 2)
}
textField.text = String(array)
index = index > 1 ? index + 2 : index + 1
let cursorPosition = textField.position(from: textField.beginningOfDocument, offset: index)!
textField.selectedTextRange = textField.textRange(from: cursorPosition, to: cursorPosition)
}
}
return false
}

how to limit uitextfield character range upto 10 digit

I just want to know how to limit uitextfield range, i.e I have one textbox in that I enter values 10 digit. If I try to type more than 10 digit my textfield should not accept the values. To be very simple I want only 10 digit should be enter in the textfield.
I work out this code but its not worked for me:
- (BOOL)textField:(UITextField *) textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSUInteger oldLength = [textField.text length];
NSUInteger replacementLength = [string length];
NSUInteger rangeLength = range.length;
NSUInteger newLength = oldLength - rangeLength + replacementLength;
BOOL returnKey = [string rangeOfString: #"\n"].location != NSNotFound;
return newLength <= MAXLENGTH || returnKey;
}
To limit a text input's length implement this method of UITextFieldDelegate and check a text's length after changing:
- (BOOL) textField:(UITextField *)textField
shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string {
NSString *resultText = [textField.text stringByReplacingCharactersInRange:range
withString:string];
return resultText.length <= 10;
}
In Swift 3.0
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let charsLimit = 10
let startingLength = textField.text?.characters.count ?? 0
let lengthToAdd = string.characters.count
let lengthToReplace = range.length
let newLength = startingLength + lengthToAdd - lengthToReplace
return newLength <= charsLimit
}
Try below code that is restricted to 10 digital text.
- (BOOL)textField:(UITextField *) textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSInteger length = [textField.text length];
if (length>9 && ![string isEqualToString:#""]) {
return NO;
}
// This code will provide protection if user copy and paste more then 10 digit text
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if ([textField.text length]>10) {
textField.text = [textField.text substringToIndex:10];
}
});
return YES;
}
Hope this help you.
Swift 3 Version
func textField(_ textField: UITextField, shouldChangeCharactersIn range:NSRange, replacementString string: String) -> Bool
{
let currentCharacterCount = textField.text?.characters.count ?? 0
if (range.length + range.location > currentCharacterCount){
return false
}
let newLength = currentCharacterCount + string.characters.count - range.length
return newLength <= 10
}
Try this.
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
if(range.length + range.location > textField.text.length)
{
return NO;
}
NSUInteger newLength = [textField.text length] + [string length] - range.length;
return (newLength > 10) ? NO : YES;}
You can use this...i hope it will help you/
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
int lenght1 = code.text.length - range.length + string.length;
if (textField.text.length >= 4 && range.length == 0)
return NO;
I built a really nice subclass of UITextField to limit the number of characters inputted into a field. Here you go!:
public class NumberFormattedTextField : UITextField {
#IBInspectable public var maximumCharacters = 10 {
didSet {
format()
}
}
public override func awakeFromNib() {
format()
addTarget(self, action: "format", forControlEvents: .EditingChanged)
}
func format() {
let len = text.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)
// truncate for max characters if needed
if len > maximumCharacters {
text = text[1...maximumCharacters] // pulls in the last entered character and drops the first one off to preserve length
}
}
}
This depends on a subscript for String. Here's that too:
public extension String {
public subscript (r: Range<Int>) -> String? {
let l = self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)
if r.startIndex <= l && r.endIndex <= l {
return substringWithRange(Range(start: advance(startIndex, r.startIndex), end: advance(startIndex, r.endIndex)))
} else {
return nil
}
}
}
I have build a subclass based on the answer given by Oxcug without the need for creating an extension in String file and max characters length can be set from storyboard and from swift file as well.:
#IBDesignable class CustomTextField: UITextField {
#IBInspectable var maximumCharacters: Int = 80 {
didSet {
limitCharacters()
}
}
override func awakeFromNib() {
super.awakeFromNib()
limitCharacters()
addTarget(self, action: #selector(CustomTextField.limitCharacters), for: .editingChanged)
}
func limitCharacters() {
guard text != nil else {
return
}
if (text?.characters.count)! > maximumCharacters {
if let range = text?.index(before: (text?.endIndex)!) {
text = text?.substring(to: range)
}
}
}
}
Best Solution:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return range.location < 10 //Here 10 is your character limit
}

UITextField : restrict the maximum allowed value (number) during inputting

I have a UITextField, I'd like to restrict the maximum allowed input value in the field to be 1000. That's when user is inputting number inside, once the input value is larger than 999, the value in input field won't be updated anymore unless user is inputting value less than 1000.
I think I should use UITextField delegate to limit the input:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
//How to do
}
But I am not sure how to implement it. Any suggestions?
==========Update=============
my input field not only allow user to input integer, but also float value like 999,03
You should do the following inside the above method:
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
//first, check if the new string is numeric only. If not, return NO;
NSCharacterSet *characterSet = [[NSCharacterSet characterSetWithCharactersInString:#"0123456789,."] invertedSet];
if ([newString rangeOfCharacterFromSet:characterSet].location != NSNotFound)
{
return NO;
}
return [newString doubleValue] < 1000;
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if(textField.tag == 3)
{
if(textField.text.length >3 && range.length == 0)
{
return NO;
}
else
{
return YES;
}
}
}
I created a class with the help method that can be call from any place in your project.
Swift code:
class TextFieldUtil: NSObject {
//Here I am using integer as max value, but can change as you need
class func validateMaxValue(textField: UITextField, maxValue: Int, range: NSRange, replacementString string: String) -> Bool {
let newString = (textField.text! as NSString).stringByReplacingCharactersInRange(range, withString: string)
//if delete all characteres from textfield
if(newString.isEmpty) {
return true
}
//check if the string is a valid number
let numberValue = Int(newString)
if(numberValue == nil) {
return false
}
return numberValue <= maxValue
}
}
Then you can use in your uiviewcontroller, in textfield delegate method with any textfield validations
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if(textField == self.ageTextField) {
return TextFieldUtil.validateMaxValue(textField, maxValue: 100, range: range, replacementString: string)
}
else if(textField == self.anyOtherTextField) {
return TextFieldUtils.validateMaxValue(textField, maxValue: 1200, range: range, replacementString: string)
}
return true
}
if([string length])
{
if (textField == txt)
{
NSString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string];
return !([newString length] > 1000);
}
}
In its most basic form you can do this:
- (BOOL)textField:(UITextField*)textField shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString*)string
{
NSString* newText;
newText = [textField.text stringByReplacingCharactersInRange:range withString:string];
return [newText intValue] < 1000;
}
However, you also need to check if newText is an integer, because intValue returns 0 when the text starts with other characters.

How can I restrict special characters in UITextField except dot and underscores?

How can I restrict special characters in a UITextField except dot and underscores?
I have tried the code snippet below, but without luck:
#define ACCEPTABLE_CHARECTERS #" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_."
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSCharacterSet *acceptedInput = [NSCharacterSet characterSetWithCharactersInString:ACCEPTABLE_CHARECTERS];
if (![[string componentsSeparatedByCharactersInSet:acceptedInput] count] > 1){
NSLog(#"not allowed");
return NO;
}
else{
return YES;
}
}
Try code block given below, it worked fine for me.
SWIFT 3.0
let ACCEPTABLE_CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let cs = NSCharacterSet(charactersIn: ACCEPTABLE_CHARACTERS).inverted
let filtered = string.components(separatedBy: cs).joined(separator: "")
return (string == filtered)
}
Objective C
#define ACCEPTABLE_CHARACTERS #" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_."
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:ACCEPTABLE_CHARACTERS] invertedSet];
NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:#""];
return [string isEqualToString:filtered];
}
Hope it will work for you as well.
Try this
NSCharacterSet *set= [NSCharacterSet symbolCharacterSet];
if ([string rangeOfCharacterFromSet:[set invertedSet]].location == NSNotFound) {
// valid
} else {
// invalid
}
you can make your own set with
NSCharacterSet *set= [NSCharacterSet characterSetWithCharactersInString:#"<all your symbols you want to ignore>"];
Swift 4
let RISTRICTED_CHARACTERS = "'*=+[]\\|;:'\",<>/?%"
UITextField delegate method:
func textField(_ textField: UITextField, shouldChangeCharactersIn _: NSRange, replacementString string: String) -> Bool {
let set = CharacterSet(charactersIn: RISTRICTED_CHARACTERS)
let inverted = set.inverted
let filtered = string.components(separatedBy: inverted).joined(separator: "")
return filtered != string
}
NSString *Regex = #"[A-Za-z0-9^]*";
NSPredicate *TestResult = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", Regex];
[TestResult evaluateWithObject:#"YourTestString"];
Last return boolean value true/false
In Method
+ (BOOL) validateSpecialCharactor: (NSString *) text {
NSString *Regex = #"[A-Za-z0-9^]*";
NSPredicate *TestResult = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", Regex];
return [TestResult evaluateWithObject:text];
}
Swift 2.2 based on Mrunal's answer:
let notAllowedCharacters = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.";
func textField(
textField: UITextField,
shouldChangeCharactersInRange range: NSRange,
replacementString string: String)
-> Bool
{
let set = NSCharacterSet(charactersInString: notAllowedCharacters);
let inverted = set.invertedSet;
let filtered = string
.componentsSeparatedByCharactersInSet(inverted)
.joinWithSeparator("");
return filtered == string;
}
Swift 3.1 solution
let ACCEPTABLE_CHARACTERS = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_."
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let cs = CharacterSet(charactersIn: ACCEPTABLE_CHARACTERS).inverted
let filtered: String = (string.components(separatedBy: cs) as NSArray).componentsJoined(by: "")
return (string == filtered)
}
This may help you try this.. and let me know please
-(BOOL)isHaveSpecialChar:(NSString*)str{
NSString *customStr = #"~`!##$%^&*()+=-/;:\"\'{}[]<>^?, ";
NSCharacterSet *alphaSet = [NSCharacterSet characterSetWithCharactersInString:customStr];
BOOL isHaveSpecialChar = [[str stringByTrimmingCharactersInSet:alphaSet] isEqualToString:#""];
return !isHaveSpecialChar;
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let set = NSCharacterSet(charactersIn: "0123456789")
let inverted = set.inverted;
let filtered = string.components(separatedBy: inverted).joined(separator: "")
return filtered == string;
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let cs = NSCharacterSet.decimalDigits.inverted
let filtered = string.components(separatedBy: cs).joined(separator: "")
return (string == filtered)
}
Try this:
NSString *str = #"___asdf.SHiv._.l.asg. g.g._ASdgASG_.......asfgads.g. .._____fdgdsfghsdfgh";
str= [str stringByReplacingOccurrencesOfString:#"." withString:#""];
str=[str stringByReplacingOccurrencesOfString:#"_" withString:#""];
str=[str stringByReplacingOccurrencesOfString:#" " withString:#""];
str=[str stringByTrimmingCharactersInSet:[NSCharacterSet alphanumericCharacterSet]];
if ([str isEqualToString:#""]) {
NSLog(#"valid");
}
else {
NSLog(#"invalid");
}

How can I limit the number of decimal points in a UITextField?

I have a UITextField that when clicked brings up a number pad with a decimal point in the bottom left. I am trying to limit the field so that a user can only place 1 decimal mark
e.g.
2.5 OK
2..5 NOT OK
Implement the shouldChangeCharactersInRange method like this:
// 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;
}
This creates an array of strings split by the decimal point, so if there is more than one decimal point we will have at least 3 elements in the array.
Here is an example with a regular expression, the example limits to only one decimal point and 2 decimals. You can tweak it to fit your needs.
- (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;
}
Swift 3 Implement this UITextFieldDelegate method to prevent user from typing an invalid number:
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
}
It is working with both comma or dot as decimal separator. You can also limit number of fraction digits using this pattern: "^[0-9]*((\\.|,)[0-9]{0,2})?$" (in this case 2).
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
}
Objective-C
//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;
}
For Swift 2.3 to prevent user for enter decimal number after two places -
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
}
}
}
}
Building on the accepted answer, the following approach validates three cases that are helpful when dealing with money formats:
Extremely large amounts
More than 2 characters after the decimal point
More than 1 decimal points
Make sure your text field's delegate is set properly, your class conforms to the UITextField protocol, and add the following delegate method.
- (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;
}
-(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];
}
}
}
}
Try this :-
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
}
Swift 3
No need to create an array and check count. Limit user can only place 1 decimal mark like this.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if (textField.text?.contains("."))! && string.contains(".")
{
return false
}
else
{
return true
}
}
Swift 4
max number of Integers Numbers is 4 i.e., 9999, and max decimal digits limit is 2. So, max number can be 9999.99
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// 100 is the tag value of our textfield
/*or you may use "if textfield == myTextField{" if you have an IBOutlet to that textfield */
if textField.tag == 100 {
//max length limit of text is 8
if textField.text!.count > 8 && string != "" {
return false
}
let maxLength = 8
let currentString: NSString = textField.text! as NSString
// Use following code If you are inputting price to that text field and want $ to get inserted automatically at start when user starts typing in that textfield or you may put some other character at start instead of $. Otherwise comment the following 3 lines of if condition code
if currentString.length == 0 {
priceTextField.text = "$"
}
//new string after inserting the new entered characters
let newString: NSString =
currentString.replacingCharacters(in: range, with: string) as NSString
if newString.length > maxLength{
return false
}
if (textField.text!.range(of: ".") != nil) {
let numStr = newString.components(separatedBy: ".")
if numStr.count>1{
let decStr = numStr[1]
if decStr.length > 2{
return false
}
}
}
var priceStr: String = newString as String
if (textField.text!.range(of: "$") != nil) {
priceStr = priceStr.replacingOccurrences(of: "$", with: "")
}
let price: Double = Double(priceStr) ?? 0
if price > 9999.99{
return false
}
switch string {
case "0","1","2","3","4","5","6","7","8","9":
return true
case ".":
let array = Array(textField.text!)
var decimalCount = 0
for character in array {
if character == "." {
decimalCount = decimalCount + 1
}
}
if decimalCount == 1 {
return false
} else {
return true
}
default:
let array = Array(string)
if array.count == 0 {
return true
}
return false
}
}
return true
}
SWIFT 5
Improvement
Info : do not allow :
separator at the beginning
zero plus another digit at the start except when you add a separator after
1: set the keyboard type to : Decimal Pad
2: copy past
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
//!\ set the keyboard type to : Decimal Pad /!\\
// CUSTOM SETUP
let c = NSLocale.current.decimalSeparator ?? "."
let limitBeforeSeparator = 2
let limitAfterSeparator = 2
// ---------
var validatorUserInput:Bool = false
let text = (textField.text ?? "") as NSString
let newText = text.replacingCharacters(in: range, with: string)
// Validator
let pattern = "(?!0[0-9])\\d*(?!\\\(c))^[0-9]{0,\(limitBeforeSeparator)}((\\\(c))[0-9]{0,\(limitAfterSeparator)})?$"
if let regex = try? NSRegularExpression(pattern: pattern, options: .caseInsensitive) {
validatorUserInput = regex.numberOfMatches(in: newText, options: .reportProgress, range: NSRange(location: 0, length: (newText as NSString).length)) > 0
}
if validatorUserInput {
// setting data or something eles before the return
if let char = string.cString(using: String.Encoding.utf8) {
let isBackSpace = strcmp(char, "\\b")
if (isBackSpace == -92 && textField.text?.count == 1) {
print("Backspace was pressed")
print(newText)
// do something...
} else {
print("Number Added")
print(newText)
// do something...
}
}
return validatorUserInput
} else {
return validatorUserInput
}
}
3: set in the method, if you want x maximum number of digits before and after the separator
let limitBeforeSeparator = 2
let limitAfterSeparator = 2
In whatever object you set your UITextField's delegate to, add a method that answers to "[- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string]".
Then you can either use a NSNumberFormatter object or you can brute force check for an already existing decimal place mark (returning NO if a decimal mark already exists).
Short told, the number format is as follows [NSString stringWithFormat:#"%9.5f", x]; Where 5 is the decimal after ",".
I made the solution, that brings you control over decimal places count, so user can type only one decimal separator and you can also have a control over decimal places count.
Just set the decimalPlacesLimit value properly.
See the method:
- (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;
}
Swift 4
The efficient and easy way to avoid multiple decimal points (. or ,) in 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([string isEqualToString:#"."]) {
BOOL containsDecimal = [textField.text containsString:#"."];
return !containsDecimal;
}
return YES;
}
If textfield text already contains a '.' then return NO else return YES.
Thanks everyone, I needed to limit the number before and after the dot. It was only with a regular expression that this became possible for me.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if string == "," {
textField.text = textField.text! + "."
return false
}
guard let newTextField = textField.text else { return false }
if !string.isEmpty {
let text = newTextField as NSString
let newText = text.replacingCharacters(in: range, with: string)
if let regex = try? NSRegularExpression(pattern: "^[0-9]{0,4}$*((\\.|,)[0-9]{0,4})?$", options: .caseInsensitive) {
return regex.numberOfMatches(in: newText, options: .reportProgress, range: NSRange(location: 0, length: (newText as NSString).length)) > 0
}
return false
}
return true
// #"^[0-9]{0,3}$*((\\.|,)[0-9]{0,2})?$"
}

Resources