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

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

一、设置textView的placeHolder

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

.h中:
#import

@interface UITextView (PlaceHolder)

@property (nonatomic, copy) NSString *placeHolder;

@end
.m中:
#import "UITextView+PlaceHolder.h"

#import

#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中输入的字数,如下页面


1.png

常规的做法就是设置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。

感谢:
//www.greatytc.com/p/b72908329ee7
详细的demo已经放在github上了,有需要的随时取用哈> https://github.com/coolLeee/TextViewHelper

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 207,113评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,644评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,340评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,449评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,445评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,166评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,442评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,105评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,601评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,066评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,161评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,792评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,351评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,352评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,584评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,618评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,916评论 2 344

推荐阅读更多精彩内容