效果展示
前奏
公司项目中,涉及到评论的功能,就需要做一个类似于微信评论框。本来我是打算从网上找一个写好的,GitHub肯定很多,我确实找了半天,不过我下载的几个真心不太符合我的要求,所以,像我微博之前说的提高主观能动性吧。自己撸一个吧。
需求:
- 评论框有placeholder
- 输入的文字超过自动折行
分析一波
这玩意肯定需要自定义,大家首先肯定想到UITextField 和 UITextView。具体用哪个呢?
UITextField 自带placeholder,UITextView自带折行。通过我观察微信的评论框,大概输入4、5行,发现是可以滚动的,不会继续增加高度。所以,这个东西就需要使用UITextView。因为UITextView是继承UIScrollView的。废话不多说,开搞。
实战
一、需要什么
在我们自定义一个控件之前,首先想到我们要怎么用,我们如何调用这个控件,决定了我们的方向。
1.1属性
我们要为使用这个轮子的朋友,提供可以修改的属性,如下:
@property (weak, nonatomic) id <ConmentToolbarDelegate> delegate;
/**
占位文字
*/
@property (strong, nonatomic) NSString *placeholder;
/**
占位文字的颜色
*/
@property (strong, nonatomic) UIColor *placeholderColor;
/**
最大行数
*/
@property (assign, nonatomic) NSInteger maxNumbersOfLine;
1.2 方法
如何调用这个类,如何简单方便的构造对象,在这个轮子里,我没有自己写个方法,考虑到后面的逻辑,当你输入完评论文字后,肯定要在vc中,处理text,所以我写了个代理方法(block写也ok)。如下:
@protocol ConmentToolbarDelegate <NSObject>
@optional
- (void)toolbar:(ConmentToolbar *)toolbar didClickSendButtonWithText:(NSString *)text;
@end
二、怎么做
1.1怎么做,就是核心的地方了。我觉得这个轮子最核心地方,就是监听textView的输入,根据文字计算文字的高度,根据高度,调整y值和高度。
监听textView使用系统自带通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChange) name:UITextViewTextDidChangeNotification object:nil];
1.2 计算思路
我的计算思路,首先根据输入文字的总高度,和设置的每一行的高度,两个相除得到,行数,根据行数改变Frame。
再加上UIView的动画效果,就和微信的差不多了。代码如下
// 文本改变时候调用
- (void)textDidChange {
// 如果textView 有文字 placeholder隐藏
self.placeholderLb.hidden = self.textView.hasText;
// NSLog(@"%@",self.textView.font);
// textView的宽度 - 左侧光标据左侧的距离 - 右侧折行据右侧距离
CGFloat w = self.textView.bounds.size.width - 10;
CGSize maxSize = CGSizeMake(w, MAXFLOAT);
// 计算文本的宽度
CGSize textSize = [self.textView.text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : self.textView.font} context:nil].size;
// 计算行数 文字的高度 / 控件高度
// 文字的总高度
CGFloat textH = ceil(textSize.height);
CGFloat tvH = self.initTextViewH - self.textView.textContainerInset.top - self.textView.textContainerInset.bottom;
CGFloat row = ceil(textH / tvH);
NSLog(@"%f -- %f",textH,tvH);
NSLog(@"row --- %f",row);
if (row > self.maxNumbersOfLine) {
self.textView.scrollEnabled = YES;
} else {
[UIView animateWithDuration:0.3 animations:^{
// 修改toolBar的 y 和 height
CGRect frame = self.frame;
frame.size.height = 44 + tvH * (row - 1);
frame.origin.y = self.initY - tvH * (row - 1);
self.frame = frame;
// 修改textView
CGFloat tvW = self.bounds.size.width - 10;
CGFloat tvH = self.bounds.size.height - 10;
CGFloat tvX = 5;
CGFloat tvY = (self.bounds.size.height - tvH) * 0.5;
self.textView.frame = CGRectMake(tvX, tvY, tvW, tvH);
}];
self.textView.scrollEnabled = NO;
}
}
1.3代理方法
// 点击发送按钮
- (void)toolbar:(ConmentToolbar *)toolbar didClickSendButtonWithText:(NSString *)text {
NSLog(@"text --- %@",text);
self.textLb.text = text;
}
// 成为第一响应者时调用
- (void)toolbarBecomeFirstResponder:(ConmentToolbar *)toolbar {
// 这里可以处理一些逻辑,我的实际项目中,需要将tableView滚动到最顶部,类似于微信展示最底部的评论内容
NSLog(@"成为第一响应者");
}
// 获取增长的文字高度
- (void)toolbar:(ConmentToolbar *)toolbar changeTextWithTextH:(NSInteger)textH {
// 这里计算出textH,根据实际逻辑来修改,其他控件高度,我的实际项目中,这个部分是调整tableView的transform
NSLog(@"textH --- %zd",textH);
}
以上就是我的核心代码,如果想看demo的来我的GitHub吧。如果大家用了有啥问题,一定告诉我十分欢迎,也麻烦在GitHub给颗小星星。
更新1:适配了Storyboard或xib加载
你只需,拖一个UIView,更改他的类所属,即可;
更新2:增加代理方法,成为第一响应者,在里面可以做一些逻辑处理,例如,将tableView滚动到最顶部,类似微信看到最底部的评论信息。
增加代理方法,暴露修改的文字高度,可以在里面出来,tableView的偏移量