iOS开发中UITextView使用小结

  最近项目开发中用到了多行文本框限制文字输入个数限制,之前的话在textViewDidChange方法中截取超出字数就可以。测试人员发现在拼音转汉字的过程中,YYTextView不会二次确认textViewDidChange方法,输入字数只能最后确认结束弹框的时候计算,影响体验效果,后转用自己封装的继承UITextView替换。另外拼音转汉字的情况下,在输入文本中间一直输入,依然会出现输入字数计算不准确的问题。下面列出解决问题实现的代码。

  

#pragma mark- UITextViewDelegate

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{

    [self.activityTextView resignFirstResponder];

}

 

-(void)updateSpeechButtonStatus{

    if (self.activityTextView.text.length >= MAX_NUM) {

        self.btnSpeech.enabled = NO;

    }else{

        self.btnSpeech.enabled = YES;

    }

}

//动态显示可输入文本字数

-(void)changeTextNumber:(UITextView *)textView{

    if (textView.text.length <= MAX_NUM) {

        self.numLabel.text = [NSString stringWithFormat:@"%lu/%lu",(unsigned long)textView.text.length,(MAX_NUM - textView.text.length)];

    }else{

        self.numLabel.text = [NSString stringWithFormat:@"%@/%@",[NSString stringWithFormat:@"%d",MAX_NUM],@"0"];

    }

}

-(void)textViewDidChange:(UITextView *)textView{

    

    UITextRange *selectedRange = [textView markedTextRange];

    //获取高亮部分

    UITextPosition *pos = [textView positionFromPosition:selectedRange.start offset:0];

    

    //如果是拼音转汉语状态不统计字数,确认输入后统计

    if (selectedRange && pos) {

        return;

    }

    

    [self changeTextNumber:textView];

    [self updateSpeechButtonStatus];

    

}

-(void)textViewDidEndEditing:(UITextView *)textView{

    textView.text = [EaseEmoji stringReplaceEmoji:textView.text];

    [self changeTextNumber:textView];

    [self updateSpeechButtonStatus];

}

 

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text

{

    BOOL isLimit = [CCCommonAPI textViewTextCountLimit:textView range:range text:text maxCount:[NSString stringWithFormat:@"%d",MAX_NUM] isAllowEmoji:YES completeBlock:^{

        //执行这里block的时候不执行textViewDidChange,block里面的内容就是textViewDidChange里面的操作

        [self changeTextNumber:textView];

        [self updateSpeechButtonStatus];

    }];

    return isLimit;

    

}

//textview字数限制处理

+ (BOOL)textViewTextCountLimit:(UITextView *)textView range:(NSRange)range text:(NSString *)text maxCount:(NSString *)maxCountStr isAllowEmoji:(BOOL)isAllowEmoji completeBlock:(nonnull CommonTextLimitCompletion)completeBlock{

    

    if (!isAllowEmoji) {

        //不允许输入表情的时候返回NO

        if ([[[UITextInputMode currentInputMode] primaryLanguage] isEqualToString:@"emoji"]) {

            return NO;

        }

    }

    

    //对于退格删除键开放限制

    if (text.length == 0) {return YES;}

        

    NSString *comcatstr = [textView.text stringByReplacingCharactersInRange:range withString:text];

    

    NSInteger caninputlen = [maxCountStr intValue] - comcatstr.length;

    

    if (caninputlen >= 0){

        return YES;

    }else{

        NSInteger len = text.length + caninputlen;

        //防止当text.length + caninputlen < 0时,使得rg.length为一个非法最大正数出错

        NSRange rg = {0,MAX(len,0)};

        

        if (rg.length > 0){

            NSString *s = @"";

            //判断是否只普通的字符或asc码(对于中文和表情返回NO)

            BOOL asc = [text canBeConvertedToEncoding:NSASCIIStringEncoding];

            if (asc) {

                s = [text substringWithRange:rg];//因为是ascii码直接取就可以了不会错

            }else{

                __block NSInteger idx = 0;

                __block NSString  *trimString = @"";//截取出的字串

                //使用字符串遍历,这个方法能准确知道每个emoji是占一个unicode还是两个

                [text enumerateSubstringsInRange:NSMakeRange(0, [text length])

                                              options:NSStringEnumerationByComposedCharacterSequences

                                           usingBlock: ^(NSString* substring, NSRange substringRange, NSRange enclosingRange, BOOL* stop) {

                                               

                                               if (idx >= rg.length) {

                                                   *stop = YES; //取出所需要就break,提高效率

                                                   return ;

                                               }

                                               

                                               trimString = [trimString stringByAppendingString:substring];

                                               

                                               idx++;

                                           }];

                

                s = trimString;

            }

            //rang是指从当前光标处进行替换处理(注意如果执行此句后面返回的是YES会触发didchange事件)

            [textView setText:[textView.text stringByReplacingCharactersInRange:range withString:s]];

            

            completeBlock();

            

            //手动截取更改,不再调用didchange

            return NO;

        }else{

            UITextRange *selectedRange = [textView markedTextRange];

            //获取高亮部分

            UITextPosition *pos = [textView positionFromPosition:selectedRange.start offset:0];

            

            if (selectedRange && pos) {

                //如果拼音转汉语状态继续输入

                return YES;

            }else{

                return NO;

            }

        }

    }

}

原文地址:https://www.cnblogs.com/bigant9527/p/15155578.html