欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

iOS UITextView问题一网打尽(占位文字、汉字输入字数计算、自动高度改变)

程序员文章站 2022-03-11 17:46:17
...

在iOS开发中,UITextView是一个使用还算比较多的控件。但是用过的人都知道,UITextView有很多存在的问题,今天就来一一说它一说。

一、设置textView的placeHolder

首先需要解决的就是占位文字placeHolder的问题,与UITextField相比,UITextView并没有相应的placeholder属性设置占位文字,但是可以通过category的方式给textView添加placeHolder属性,这样就可以在任何需要的使用直接使用了,我写好了一个category UITextView+PlaceHolder,大概如下:
.h中

#import <UIKit/UIKit.h>

@interface UITextView (PlaceHolder)

@property (nonatomic, copy) NSString *placeHolder;

@end

.m中:

#import "UITextView+PlaceHolder.h"
#import <objc/runtime.h>

#define kScreenW [UIScreen mainScreen].bounds.size.width
static const void *textView_key = @"placeHolder";

@interface UITextView ()
@end

@implementation UITextView (PlaceHolder)

- (void)setPlaceHolder:(NSString *)placeHolder
{
    if (placeHolder != self.placeHolder) {
        objc_setAssociatedObject(self, textView_key, placeHolder, OBJC_ASSOCIATION_COPY_NONATOMIC);

        UILabel *placeHolderLb = [[UILabel alloc] initWithFrame:CGRectMake(2, 7, kScreenW-2*16, 21)];
        placeHolderLb.tag = 1000;
        placeHolderLb.contentMode = UIViewContentModeTop;
        placeHolderLb.numberOfLines = 0;
        placeHolderLb.textColor = [UIColor redColor];
        placeHolderLb.font = [UIFont systemFontOfSize:16];
        placeHolderLb.alpha = 1;
        placeHolderLb.text = placeHolder;
        [self addSubview:placeHolderLb];

        //之所以使用通知形式是为了不影响textView的delegate方法,否则别的地方- (void)textViewDidChange:(UITextView *)textView这个代理不会再执行
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textViewChanged:) name:UITextViewTextDidChangeNotification object:nil];
    }
}

- (NSString *)placeHolder
{
    return objc_getAssociatedObject(self, textView_key);
}

- (void)textViewChanged:(NSNotification *)noti
{
    UILabel *label = [self viewWithTag:1000];
    if (self.text.length == 0) {
        label.alpha = 1;
    } else {
        label.alpha = 0;
    }
}

如需修改placeHolder的字体大小或者颜色之类的,可以直接在.m中修改,也可以自己再给textView添加相应的属性,这里就不再叙述。

二、输入汉字时字数统计

开发中这样的需求也不少见,需要实时统计textView中输入的字数,如下页面
iOS UITextView问题一网打尽(占位文字、汉字输入字数计算、自动高度改变)
常规的做法就是设置textView的delegate,实现delegate中的- (void)textViewDidChange:(UITextView *)textView,然后统计输入文字的个数,
当然这对于统计英文和数字来说,一般都是没有问题的,但是到统计中文的时候就出现了问题。当用户连续输入拼音,还未选择内容时,其实上面的方法已经执行了,也就是说每次输入拼音都会走上面的代理,这就很尴尬了,实时显示的字数,就会一直跳来跳去,这怎么办呢?别急,统计汉字字数有轻功,少侠且往下看:
实现`(void)textViewDidChange:(UITextView *)textView“这个代理,但是在里面需要做点处理

- (void)textViewDidChange:(UITextView *)textView
{
    NSInteger maxFontNum = 200;//最大输入限制
    NSInteger length = self.textView.text.length;
    NSString *toBeString = textView.text;
    // 获取键盘输入模式
    NSString *lang = [[UIApplication sharedApplication] textInputMode].primaryLanguage;
    if ([lang isEqualToString:@"zh-Hans"]) { // zh-Hans代表简体中文输入,包括简体拼音,健体五笔,简体手写
        UITextRange *selectedRange = [textView markedTextRange];
        //获取高亮部分
        UITextPosition *position = [textView positionFromPosition:selectedRange.start offset:0];
        // 没有高亮选择的字,则对已输入的文字进行字数统计和限制
        if (!position) {
            if (toBeString.length > maxFontNum) {
                textView.text = [toBeString substringToIndex:maxFontNum];//超出限制则截取最大限制的文本
                self.textCountLabel.text = [NSString stringWithFormat:@"%ld/200",maxFontNum];
            } else {
                self.textCountLabel.text = [NSString stringWithFormat:@"%ld/200",toBeString.length];
            }
        }
    } else {// 中文输入法以外的直接统计
        if (toBeString.length > maxFontNum) {
            textView.text = [toBeString substringToIndex:maxFontNum];
            self.textCountLabel.text = [NSString stringWithFormat:@"%ld/200",maxFontNum];
        } else {
            self.textCountLabel.text = [NSString stringWithFormat:@"%ld/200",toBeString.length];
        }
    }
}

根据键盘类型进行判断,如果输入的是中文,则判断是否为高亮文字即连续输入的拼音,如果不是高亮的则直接进行字数统计,否则不作处理,这样就解决了字数统计的问题。
**

三、tableViewCell中textView的高度自适应

**
cell中有textView,想实现的效果是当textView中输入文字的时候,textView和cell的高度都随着输入文字的高度进行自适应,对cell高度自适应还没有概念的可以看看这篇文章,这里就不多讲了。要做到高度自适应,还是要在- (void)textViewDidChange:(UITextView *)textView中实现,接着上面获取输入字数的实现继续:

- (void)textViewDidChange:(UITextView *)textView
{
    NSInteger maxFontNum = 200;//最大输入限制
    NSInteger length = self.textView.text.length;
    NSString *toBeString = textView.text;
    // 获取键盘输入模式
    NSString *lang = [[UIApplication sharedApplication] textInputMode].primaryLanguage;
    if ([lang isEqualToString:@"zh-Hans"]) { // zh-Hans代表简体中文输入,包括简体拼音,健体五笔,简体手写
        UITextRange *selectedRange = [textView markedTextRange];
        //获取高亮部分
        UITextPosition *position = [textView positionFromPosition:selectedRange.start offset:0];
        // 没有高亮选择的字,则对已输入的文字进行字数统计和限制
        if (!position) {
            if (toBeString.length > maxFontNum) {
                textView.text = [toBeString substringToIndex:maxFontNum];//超出限制则截取最大限制的文本
                self.textCountLabel.text = [NSString stringWithFormat:@"%ld/200",maxFontNum];
            } else {
                self.textCountLabel.text = [NSString stringWithFormat:@"%ld/200",toBeString.length];
            }
        }
    } else {// 中文输入法以外的直接统计
        if (toBeString.length > maxFontNum) {
            textView.text = [toBeString substringToIndex:maxFontNum];
            self.textCountLabel.text = [NSString stringWithFormat:@"%ld/200",maxFontNum];
        } else {
            self.textCountLabel.text = [NSString stringWithFormat:@"%ld/200",toBeString.length];
        }
    }

    //高度自适应
    CGFloat height = [textView.text boundingRectWithSize:CGSizeMake(self.textView.width, CGFLOAT_MAX) options:NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16]} context:nil].size.height;
    if (height >= 80) {
        self.textViewHeightConstant.constant = height;
    } else {
        self.textViewHeightConstant.constant = 80;
    }

    [self.tableView beginUpdates];
    [self.tableView endUpdates];
}

这里有几个重点:
1.最重要的一点,设置tableView的scrollEnabled=NO,如果不正确设置此值,不会实现高度自适应的效果。
2.给textView添加约束时,要设置textView的height为>=某个值,比如我这里的>=80,接着拖出这个约束,上面的textViewHeightConstant就是textView高度的约束。然后根据计算出的文字高度判断是否需要cell和textView伸缩
3.要实时更新tableView中cell的frame,通过[self.tableView beginUpdates];
[self.tableView endUpdates];
来更改。这里的self.tableView是我在cell中添加的tableView这个属性,也可以通过self.superView获取当前的tableView。

详细的demo已经放在github上了,有需要的随时取用哈

https://github.com/coolLeee/TextViewHelper