提问
1.自适应cell高度,你会几种?
2.约束,局部,适配 你会几种?
- textview 是否会自定义高度。
这里textview实现的cell IOS 8 自适应方法。 使用Masonry布局,使用runtimer给分类,进行动态添加方法,和交换方法。
整体的逻辑,textview ,首先自适应高度,然后把高度和输入的字符用block 的方式,传到cell里,viewController通过代理事件,进行更新自适应高度!
我试过很多方法,和各种回调,还是不能达到预期的效果,就是解决不了cell跟着更新!(这个很皮啊!)
难点,在于textview,和cell的结合,textview怎么样才能实时的自适应来适应高度,这里肯定想要了用KVO KVC 观察着啊,但是这些我都无法很巧妙和结合起来使用,也没有达到预期的效果bug一大推! 然后去github上找了找,发现尽然用到runtimer! 于是就下了狠心一定要把这个东西给弄懂!
下面我一步一步的解读下来
首先我们看,viewconeroller做了些啥。。!
self.dataSource = [NSMutableArray array];
for (NSInteger i = 0; i < 6; i++) {
[self.dataSource addObject:@""];
}
if (!_titls) {
_titls = [NSMutableArray array];
for (int i = 1; i<100; i++) {
[_titls addObject:[NSString stringWithFormat:@"%d.",i]];
}
}
return _titls;
//创建了一个cell,设置了一个代理。给控件赋值了!
LSTextViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
cell.delegate = self;
cell.textView.text = self.dataSource[indexPath.row];
cell.label.text = self.titls[indexPath.row];
//通过cell 的出indexpath,获得cell的绑定indexpath
-(void)textViewCell:(LSTextViewCell *)cell textChange:(NSString )text{
NSIndexPath indexPath = [self.tableView indexPathForCell:cell];
[self.DatasoucerDit setValue:text forKey:[NSString stringWithFormat:@"%ld",indexPath.row]];
if (!indexPath) {
return;
}
//将对象anObject插入数组的index元素
[self.dataSource replaceObjectAtIndex:indexPath.row withObject:text];
}
//更新
-(void)textViewCell:(LSTextViewCell)cell textHeightChange:(NSString)text{
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
//在上面,就实例化出来了cell,赋值,遵从了一个delegate;代理分别是一个更新和取值的方法。
//在来看cell这个控件做了啥
控件的添加我就不说了!
-(void)textViewDidChange:(UITextView *)textView{
if (self.textView.text.length > self.maxNumberWords && self.maxNumberWords > 0) {
self.textView.text = [self.textView.text substringToIndex:self.maxNumberWords-1];
}
//判断delegate 是否为空,判断是否响应了 dalegate方法
if (self.delegate && [self.delegate respondsToSelector:@selector(textViewCell:textChange:)]) {
//代理传值,这个是text改变!
//这个是更新tableview
[self.delegate textViewCell:self textChange:self.textView.text];
}
}
这个方法就是限制text的,给viewcontroller的text ,做了一个限制字符的输入!
[self.textView setHeightDidChangeBlock:^(NSString *text, CGFloat height) {
[weakSelf.textView mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_greaterThanOrEqualTo(@(height)).priority(888);
}];
//高度改变,这个就把text 传出去了。。
if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(textViewCell:textHeightChange:)]) {
[weakSelf.delegate textViewCell:weakSelf textHeightChange:text];
}
[weakSelf layoutIfNeeded];
}];
//这里也只是改变约束,设置自适应
[self.textView setTextDidSetBlock:^(NSString *text, CGFloat textHeight) {
[weakSelf.textView mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_greaterThanOrEqualTo(@(textHeight)).priority(888);
}];
[weakSelf layoutIfNeeded];
}];
上面就算完了,逻辑都没在里面写的,重头戏来了。。
自定义的textview,主要做了写什么呢?
首先设置本身的属性让他不能够滚动自适应起来来。
监听Text属性值的变化
sizeThatFits 这个方法返回实际的尺寸,ceil 在向上取整
在判断是否 高度变化,给他传出去给cell去修改约束
可以说到这里就已经结束了一切的代码了。你的cell 和textview都已经可以自适应了。
但是他还是不完美的,他不能设置占位符,没有提示符。
这样的话,就只有使用runtime来设置了。。
其实说白了,就给他动态添加属性就行了,不过这个你不能乱添加你要看下需要的属性是不是能够跟你拿来做临时的UI 能够很好的结合,这样的话,你写起来就方便!
提示符,提示符的颜色,和花字体,全部都用一个lable来代替! 因为labe全部都有相同的属性!这样就很方便了。。我直接set方法在我内部修改就OK了。
然后你得把lable的frame算出来,还有是否显示。(这里方法有很多种)
作者用的确实,比较难的! 使用观察者 不知道为什么作者那么喜欢观察者模式!(个人认为观察者是比较麻烦的,还有很容易出问题),作者这里就会出问题,因为你要考虑到他的销毁!
这里作者有来搞runtime!
他把方法dealloc方法交互,去销毁观察者!和通知!