In development, there are times when you need to have a maximum word limit for an input field. For example, limit the length of user nicknames, comment maximum word limit.

When we started, we usedshouldChangeCharactersInRange

Stackoverflow.com/questions/4…





This is ok if the input is all in English. But when the input is in Chinese, because shouldChangeCharactersInRange judgment is the number of characters of the current keyboard, there will be such a problem: For example, if you have two characters left to type, and you want to type “Zhang SAN “, the pinyin of” Zhang “is Zhang, you can’t type in Zh. Obviously, this is not what we want.

The pinyin and shouldChangeCharactersInRange no responses to the process of Chinese characters.

Then I found a basic solution here:

Blog.sina.com.cn/s/blog_60f9…

Registered in viewDidLoad < UITextFieldTextDidChangeNotification > notifications.

[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(textFiledEditChanged:) 
          name:@"UITextFieldTextDidChangeNotification" object:myTextField];Copy the code

Then implement the listening method:

- (void)textFiledEditChanged:(NSNotification *)obj{   
   UITextField *textField = (UITextField *)obj.object;     
   NSString *toBeString = textField.text;  
   NSString *lang = [[UITextInputMode currentInputMode] primaryLanguage]; // Keyboard input mode
   if ([lang isEqualToString:@"zh-Hans"]) { // Simplified Chinese input, including simplified Pinyin, Jianli Wubi, simplified handwriting
      UITextRange *selectedRange = [textField markedTextRange];       // Get the highlighted part
      UITextPosition *position = [textFieldpositionFromPosition:selectedRange.start offset:0];       
      // If the selected word is not highlighted, the entered word counts and limits
      if(! position) {if(toBeString.length > kMaxLength) { textField.text = [toBeString substringToIndex:kMaxLength]; }}// If there is a highlighted selection of the string, the text will not be counted and restricted
       else{}}// If the input method is not Chinese, it can be counted directly. Else {
       if(toBeString.length > kMaxLength) { textField.text = [toBeString substringToIndex:kMaxLength]; }}}Copy the code

Everything seemed, seemed to be going well. This is done by intercepting characters. Then my tutor told me to hang up when I see an emoji. Suppose the input limit is 15 characters. If the input of the 15th character is emoji, emoji cannot be displayed normally. Because emoji are two characters in size.

Here, then, is an idea to prevent this kind of rude truncation.

Stackoverflow.com/questions/1…

Use rangeOfComposedCharacterSequencesForRange, prevent the whole word within the range be truncated. However, iOS seems not to be able to correctly recognize composed character sequences in Chinese. Any two Chinese characters will be recognized as composed character sequences. Coincidentally, currentInputMode is not zh-hans when typing emoji. Therefore, if the current Mode input is Chinese, you can continue to truncate it by using substringToIndex. In non-Chinese Mode, judge. The code is as follows:

#pragma mark - Notification Method- (void)textFieldEditChanged:(NSNotification *)obj
{
    UITextField *textField = (UITextField *)obj.object;
    NSString *toBeString = textField.text;
    NSString *lang = [textField.textInputMode primaryLanguage];
    if ([lang isEqualToString:@"zh-Hans"])// Enter in simplified Chinese
    {
        // Get the highlighted part
        UITextRange *selectedRange = [textField markedTextRange];
        UITextPosition *position = [textField positionFromPosition:selectedRange.start offset:0];

        // If the selected word is not highlighted, the entered word counts and limits
        if(! position) {if(toBeString.length > MAX_STARWORDS_LENGTH) { textField.text = [toBeString substringToIndex:MAX_STARWORDS_LENGTH]; }}}// If the input method is not Chinese, the statistics of other languages are not considered
    else
    {
        if (toBeString.length > MAX_STARWORDS_LENGTH)
        {
            NSRange rangeIndex = [toBeString rangeOfComposedCharacterSequenceAtIndex:MAX_STARWORDS_LENGTH];
            if (rangeIndex.length == 1)
            {
                textField.text = [toBeString substringToIndex:MAX_STARWORDS_LENGTH];
            }
            else
            {
                NSRange rangeRange = [toBeString rangeOfComposedCharacterSequencesForRange:NSMakeRange(0, MAX_STARWORDS_LENGTH)]; textField.text = [toBeString substringWithRange:rangeRange]; }}}}Copy the code

Take a look at the modified nicknames of wechat,QQ and Zhihu. Wechat counts English characters as one length, Chinese characters as two lengths, and emoji as four lengths. The total length is 32. When you enter more than the specified length of Chinese characters, force the current keyboard input to English. If the number of characters left is less than or equal to 3, no emoji can be entered. QQ also calculates the length of English characters and Chinese characters separately, but when there is only one length left, the keyboard cannot input the full Chinese pinyin. That is, the < Zhang SAN > example mentioned above. But it doesn’t matter if you’re modifying your nickname. If it’s something that requires a review, there’s still room for experience optimization. Zhihu second goods unexpectedly no length limit, but modify the nickname unexpectedly need to review…

October 14 update later found that third-party input method (such as Sogou, Baidu input method) will appear error, found that only need so on the line.

    UITextField *textField = (UITextField *)obj.object;
    NSString *toBeString = textField.text;

    // Get the highlighted part
    UITextRange *selectedRange = [textField markedTextRange];
    UITextPosition *position = [textField positionFromPosition:selectedRange.start offset:0];

    // If the selected word is not highlighted, the entered word counts and limits
    if(! position) {if (toBeString.length > MAX_STARWORDS_LENGTH)
        {
            NSRange rangeIndex = [toBeString rangeOfComposedCharacterSequenceAtIndex:MAX_STARWORDS_LENGTH];
            if (rangeIndex.length == 1)
            {
                textField.text = [toBeString substringToIndex:MAX_STARWORDS_LENGTH];
            }
            else
            {
                NSRange rangeRange = [toBeString rangeOfComposedCharacterSequencesForRange:NSMakeRange(0, MAX_STARWORDS_LENGTH)];
                textField.text= [toBeString substringWithRange:rangeRange]; }}}Copy the code