manatee
manatee

Reputation: 185

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
}

Upvotes: 3

Views: 4886

Answers (5)

Jigar Tarsariya
Jigar Tarsariya

Reputation: 3247

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.

Upvotes: 3

Barcenas
Barcenas

Reputation: 76

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
}

Upvotes: -1

damjandd
damjandd

Reputation: 707

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
  }

Upvotes: 7

W.K.S
W.K.S

Reputation: 10095

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

Upvotes: 1

Bhadresh Kathiriya
Bhadresh Kathiriya

Reputation: 3244

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;
}

Upvotes: 0

Related Questions