iOS UITextView问题一网打尽(占位文字、汉字输入字数计算、自动高度改变)
在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中输入的字数,如下页面
常规的做法就是设置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是我在cell中添加的tableView这个属性,也可以通过self.superView获取当前的tableView。
[self.tableView endUpdates];
详细的demo已经放在github上了,有需要的随时取用哈