美文网首页
iOS UITextField输入字数限制(包括Emoji)

iOS UITextField输入字数限制(包括Emoji)

作者: 策棋 | 来源:发表于2018-03-30 09:19 被阅读0次

    写在前面:

    iOSUITextField的输入字数限制,网上有很多版本,但是似乎都不能满足我们项目的需求(例:输入框长度限制为10位,在输入过程中进行限制,其中包括输入Emoji),于是自己实现了该功能。

    主要思想:

    监听UITextField的shouldChangeCharactersInRange方法,获取输入内容stringrange,此时获取剩余可输入字符个数(NSInteger remainTextCount = maxTextCount - textField.text.length + range.length;)
    string进行判断,如果包含Emoji,则获取Emoji的LocationLength,若可以追加在textField.text中,则调用replaceCharactersInRangewithString方法进行替换,最后设定光标位置setSelectedTextRange

    核心代码:

    /**
     * 输入框内容监听方法
     *
     * 输入框内容监听方法
     *
     * @return 是否许可输入内容  返回值:YES:许可   NO:输入禁止
     */
    - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
        // 删除按钮点击
        if ([string isEqualToString:@""]) {
            return YES;
        }
        // 最大可输入字符数
        NSInteger maxTextCount = 10;
        
        NSMutableAttributedString *textFieldString = [[NSMutableAttributedString alloc] initWithString:textField.text];
        // 剩余可输入字符数
        NSInteger remainTextCount = maxTextCount - textFieldString.length + range.length;
        if (remainTextCount < 0) {
            remainTextCount = 0;
        }
        
       // 输入内容中包含Emoji
        if ([self stringContainsEmoji:string]) {
            // 输入内容的长度在可输入字符数的范围内
            if (string.length <= remainTextCount) {
                [textFieldString replaceCharactersInRange:range withString:string];
                textField.text = textFieldString.string;
                
                // 开始位置
                UITextPosition *beginning = textField.beginningOfDocument;
                // 光标开始位置
                UITextPosition *startPosition = [textField positionFromPosition:beginning offset:range.location + string.length];
                // 光标结束位置
                UITextPosition *endPosition = [textField positionFromPosition:beginning offset:range.location + string.length];
                // 光标选择区域
                UITextRange *selectionRange = [textField textRangeFromPosition:startPosition toPosition:endPosition];
                [textField setSelectedTextRange:selectionRange];
            }
            // 输入内容的长度超过可输入字符数的范围内
            else {
                // 获取字符串实际截取Index
                [self stringContainsEmoji:string maxCount:remainTextCount resultBlock:^(NSInteger toIndex) {
                    NSString *changeString = [string substringToIndex:toIndex];
                    [textFieldString replaceCharactersInRange:range withString:changeString];
                    textField.text = textFieldString.string;
                    
                    UITextPosition *beginning = textField.beginningOfDocument;
                    UITextPosition *startPosition = [textField positionFromPosition:beginning offset:range.location + changeString.length];
                    UITextPosition *endPosition = [textField positionFromPosition:beginning offset:range.location + changeString.length];
                    UITextRange *selectionRange = [textField textRangeFromPosition:startPosition toPosition:endPosition];
                    [textField setSelectedTextRange:selectionRange];
                }];
            }
            return NO;
        }
        // 输入内容中无Emoji 并且 输入内容的长度超过可输入字符数的范围内
        else if (string.length > remainTextCount) {
            NSString *changeString = [string substringToIndex:remainTextCount];
            [textFieldString replaceCharactersInRange:range withString:changeString];
            textField.text = textFieldString.string;
            
            UITextPosition *beginning = textField.beginningOfDocument;
            UITextPosition *startPosition = [textField positionFromPosition:beginning offset:range.location + changeString.length];
            UITextPosition *endPosition = [textField positionFromPosition:beginning offset:range.location + changeString.length];
            UITextRange *selectionRange = [textField textRangeFromPosition:startPosition toPosition:endPosition];
            [textField setSelectedTextRange:selectionRange];   
            return NO;
        }
        return YES;
    }
    
    /**
     * 输入字符串中是否包含Emoji
     *
     * @return 是否存在Emoji  返回值:YES:存在   NO:不存在
     */
    - (BOOL)stringContainsEmoji:(NSString *)string {
        __block BOOL returnValue = NO;
        [string enumerateSubstringsInRange:NSMakeRange(0, [string length])
                                   options:NSStringEnumerationByComposedCharacterSequences
                                usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
                                    const unichar high = [substring characterAtIndex: 0];
                                    
                                    // Surrogate pair (U+1D000-1F9FF)
                                    if (0xD800 <= high && high <= 0xDBFF) {
                                        const unichar low = [substring characterAtIndex: 1];
                                        const int codepoint = ((high - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000;
                                        
                                        if (0x1D000 <= codepoint && codepoint <= 0x1F9FF){
                                            returnValue = YES;
                                        }
                                        
                                        // Not surrogate pair (U+2100-27BF)
                                    } else {
                                        if (0x2100 <= high && high <= 0x27BF){
                                            returnValue = YES;
                                        }
                                    }
                                }];
        return returnValue;
    }
    
    /**
     * 获取字符串的最大输入Index
     *
     * @param[in] string 输入字符串
     * @param[in] maxCount 最大输入字符数
     * @param[out] block 结果Block
     */
    - (void)stringContainsEmoji:(NSString *)string maxCount:(NSInteger)maxCount resultBlock:(void (^)(NSInteger))block {
        __block BOOL returnValue = NO;
        __block NSMutableArray *emojiRangeArr = [NSMutableArray array];
        [string enumerateSubstringsInRange:NSMakeRange(0, [string length])
                                   options:NSStringEnumerationByComposedCharacterSequences
                                usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
                                    const unichar high = [substring characterAtIndex: 0];
                                    
                                    // Surrogate pair (U+1D000-1F9FF)
                                    if (0xD800 <= high && high <= 0xDBFF) {
                                        const unichar low = [substring characterAtIndex: 1];
                                        const int codepoint = ((high - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000;
                                        
                                        if (0x1D000 <= codepoint && codepoint <= 0x1F9FF){
                                            returnValue = YES;
                                            [emojiRangeArr addObject:@[@(substringRange.location), @(substringRange.length)]];
                                        }
                                        
                                        // Not surrogate pair (U+2100-27BF)
                                    } else {
                                        if (0x2100 <= high && high <= 0x27BF){
                                            returnValue = YES;
                                            [emojiRangeArr addObject:@[@(substringRange.location), @(substringRange.length)]];
                                        }
                                    }
                                }];
        NSInteger returnToIndex = maxCount;
        if (returnValue) {
            for (NSArray *subArr in emojiRangeArr) {
                NSUInteger location = [[subArr firstObject] integerValue];
                NSUInteger length = [[subArr lastObject] integerValue];
                
                if (location < maxCount) {
                    if (location + length > maxCount) {
                        returnToIndex = location;
                    }
                }
            }
        }
        block(returnToIndex);
        
    }
    

    写在前面:

    代码还可优化,欢迎指正。

    相关文章

      网友评论

          本文标题:iOS UITextField输入字数限制(包括Emoji)

          本文链接:https://www.haomeiwen.com/subject/zdhvcftx.html