美文网首页
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