67

Is there any way to set the maximum length on a UITextField?

Something like the MAXLENGTH attribute in HTML input fields.

typeoneerror
  • 55,990
  • 32
  • 132
  • 223
EldenChris
  • 1,059
  • 1
  • 10
  • 16

11 Answers11

243

This works correctly with backspace and copy & paste:

#define MAXLENGTH 10

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

UPDATE: Updated to accept the return key even when at MAXLENGTH. Thanks Mr Rogers!

Tomas Andrle
  • 13,132
  • 15
  • 75
  • 92
  • 1
    This answer is the only one that actually works when the user tries to paste in a long string. Please upvote! – JosephH Mar 05 '12 at 10:56
  • This answer works perfectly. The accepted answer does not work, as the user can enter one more character than MAXLENGTH. – Evan Mulawski Apr 24 '12 at 20:59
  • If they're pasting, should it not paste up until they hit the limit? – Philippe Sabourin Aug 01 '12 at 23:09
  • @PhilippeSabourin I don't think that's possible. This API only allows us to say YES or NO to the entire block of text. – Tomas Andrle Aug 02 '12 at 09:04
  • Could you set the textfield.text to however much you can before returning NO? – Philippe Sabourin Aug 02 '12 at 13:07
  • @PhilippeSabourin I wouldn't do that because I don't think it is a correct way to use this API but you can certainly try it. – Tomas Andrle Aug 02 '12 at 15:12
  • 2
    I had a problem where the Done key wouldn't get registered if I was already at `MAXLENGTH`. I had to look for newline characters if at `MAXLENGTH` and return `YES` still. Thanks for the help! – Mr Rogers Sep 04 '12 at 17:56
  • Awesome answer. It would be great if there was a way to make this a subclass, category, or SOMETHING, so that one never had to do this again. It would have to allow for setting the length, individually, for each text field in a project. – Fattie Apr 13 '14 at 20:43
  • 1
    Small suggestion for performance: do not put the returnKey check in a separate bool. Now you are checking for a return although most of the time newLength will be smaller than MAXLENGTH. Remove the BOOL line and replace the last line with: `return newLength <= maxLength || ([string rangeOfString: @"\n"].location != NSNotFound);` – Yvo Jul 25 '14 at 09:02
  • 1
    Not work for Chinese chracters input – ZYiOS Jul 28 '14 at 07:49
41

UPDATE

I cannot delete this answer because it is the accepted one, but it was not correct. Here is the correct code, copied from TomA below:

#define MAXLENGTH 10

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

ORIGINAL

I think you mean UITextField. If yes, then there is a simple way.

  1. Implement the UITextFieldDelegate protocol
  2. Implement the textField:shouldChangeCharactersInRange:replacementString: method.

That method gets called on every character tap or previous character replacement. in this method, you can do something like this:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    if ([textField.text length] > MAXLENGTH) {
        textField.text = [textField.text substringToIndex:MAXLENGTH-1];
        return NO;
    }
    return YES;
}
coneybeare
  • 33,113
  • 21
  • 131
  • 183
  • 1
    Yes I was meaning UITextField, I edited my question. I got it. Thanks for your answer. It works for me ! – EldenChris Mar 26 '10 at 13:42
  • 1
    You also need to assign the proper delegate to de UITextField. – Ecarrion Jul 15 '11 at 17:18
  • 11
    This is somewhat flawed: 1) by checking the existing field text length (and not the proposed new length) you allow the user to go 1 character beyond the maximum, and 2) it doesn't prevent users from copy-and-pasting more text in. – Craig McMahon Dec 21 '11 at 08:13
  • 3
    It should be `>= MAXLENGTH` and `substringToIndex:MAXLENGTH`. – Evan Mulawski Apr 24 '12 at 00:15
  • Your code sample does not work on iOS 5 (MAXLENGTH = 5). I can enter 6 characters. When I try to enter another character, it removes the 6th character. My correction in the comment above does not completely fix the problem either. TomA's answer works perfectly. – Evan Mulawski Apr 24 '12 at 20:58
  • 3
    This solution is quite bad.. if you set maxlength to 2 you can actually enter 6 characters. Also nothing happens when you press the backspace button on the keyboard. and thirdly, when keep typing, it will replace the previous string. Please see this answer, which works much better http://stackoverflow.com/questions/433337/iphone-sdk-set-max-character-length-textfield – Erik Feb 12 '13 at 04:08
  • This old answer was never meant to be a copy/paste job, but a place to show you where to hook in the custom logic you can determine for your own app. You will be a much better engineer when someone shows you how to solve the problem instead of giving you the answer. – coneybeare Feb 12 '13 at 04:17
17

A better function which handles backspaces correctly and limits the characters to the supplied length limit is the following:

#define MAXLENGTH 8

    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
    {
        int length = [textField.text length] ;
        if (length >= MAXLENGTH && ![string isEqualToString:@""]) {
            textField.text = [textField.text substringToIndex:MAXLENGTH];
            return NO;
        }
        return YES;
    }

Cheers!

Stunner
  • 12,025
  • 12
  • 86
  • 145
Varun Chatterji
  • 5,059
  • 1
  • 23
  • 24
12

This code limits the text while also allowing you enter characters or paste anywhere into the text. If the resulting text would be too long it changes the characters in the range and truncates the resulting text to the limit.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    NSUInteger newLength = [textField.text length] - range.length + [string length];
    if (newLength >= MAXLENGTH) {
        textField.text = [[textField.text stringByReplacingCharactersInRange:range withString:string] substringToIndex:MAXLENGTH];
        return NO;
    }
    return YES;
}
Andy Bradbrook
  • 355
  • 3
  • 6
4

I think this code would do the trick:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range 
                                                       replacementString:(NSString*)string
{
   if (range.location >= MAX_LENGTH)
      return NO;
    return YES;
}

With this delegate method you can prevent the user to add more characters than MAX_LENGTH to your text field and the user should be allowed to enter backspaces if needed.

  • 1
    This doesn't fully cover the case where the user is pasting; it allows the string to become too long. – JosephH Mar 05 '12 at 10:50
2

this is how i resolved that problem. When max limit is reached it wont try to add more... you will only be able to remove chars

#define MAX_SIZE ((int) 5)
...

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    if ([textField.text length] >= MAX_SIZE && ![string isEqualToString:@""]) {
        return NO;
    }

    return YES;
}
Peter Kreinz
  • 7,979
  • 1
  • 64
  • 49
pedrotorres
  • 1,222
  • 2
  • 13
  • 26
2

For me this did the magic:

if (textField.text.length >= 10 && range.length == 0)
    return NO;
return YES;
Bo Persson
  • 90,663
  • 31
  • 146
  • 203
vishwa.deepak
  • 510
  • 4
  • 18
1

You have to be aware of the location the text is placed in as well as the length of text being added (in case they're pasting more than one character). The pattern between these with respect to max length is that their sum should never exceed the max length.

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    NSInteger locationAndStringLengthSum = range.location + [string length];

    if ([textField isEqual:_expirationMonthField]) {
        if (locationAndStringLengthSum > EXP_MONTH_FIELD_MAX_CHAR_LENGTH) {
            return NO;
        }
    }
    else if ([textField isEqual:_expirationYearField]) {
        if (locationAndStringLengthSum > EXP_YEAR_FIELD_MAX_CHAR_LENGTH) {
            return NO;
        }
    }
    else if ([textField isEqual:_securityCodeField]) {
        if (locationAndStringLengthSum > SECURITY_FIELD_MAX_CHAR_LENGTH) {
            return NO;
        }
    }
    else if ([textField isEqual:_zipCodeField]) {
        if (locationAndStringLengthSum > ZIP_CODE_MAX_CHAR_LENGTH) {
            return NO;
        }
    }

    return YES;
}
David Robles
  • 373
  • 1
  • 8
  • 13
1

I think there's no such property.

But the text you assign to the UILabel has to be an NSString. And before you assign this string to the UILabel's text property you can for example use the following method of NSString to crop the string at a given index (your maxlength):

- (NSString *)substringToIndex:(NSUInteger)anIndex
schaechtele
  • 1,130
  • 1
  • 9
  • 12
  • 1
    Unfortunately the question asker changed their question after you answered, so your answer no longer makes any sense :( – JosephH Mar 05 '12 at 10:53
1

This is similar to coneybeare's answer, but now the text field can contain a maximum of MAXLENGTH symbols:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    if ([textField.text length] > MAXLENGTH - 1) {
        textField.text = [textField.text substringToIndex:MAXLENGTH];
        return NO;
    }
    return YES;
}
Michael Myers
  • 188,989
  • 46
  • 291
  • 292
objcdev.ru
  • 19
  • 1
  • This one doesn't prevent the length going over the maximum when the user pastes a string longer than 1. – Shebuka Jul 29 '14 at 10:22
-3

You need to assign delegate on ViewDidLoad

TextFieldname.delegate=self
Kirk Woll
  • 76,112
  • 22
  • 180
  • 195