因为公司项目的计算高度library,经常在ios7的几个little version上发生crash,特发此文。
要求Version >= IOS7.0
高度计算的历程
<pre>
- calucate manully,通过
[self.userComment.text boundingRectWithSize:<#(CGSize)#> options:<#(NSStringDrawingOptions)#> attributes:<#(nullable NSDictionary<NSString *,id> *)#> context:<#(nullable NSStringDrawingContext *)#>]<bre>
[self.userComment sizeThatFits:<#(CGSize)#>];
这样的方法来计算高度,最后把各种 margin 、labelHeight、textviewHeigt加在一起,逐步计算。
- 在AutoLayout大家都认可之后,开始使用systemLayoutSizeFittingSize来计算高度
- 然后就是iOS8的 self-sizing cell ,使用 frame layout 和 auto layout 都可以。
self.tableView.estimatedRowHeight = 213;
self.tableView.rowHeight = UITableViewAutomaticDimension;
</pre>
好了下面进入正题。
首先计算高度,如果是固定高度,强烈推荐使用self.tableView.rowHeight
这个属性来设置高度,这样就避免了,计算。让界面更加的流畅,你懂得。
如果你重写了代理方法。
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
刚开始设置的属性会被覆盖。
下一个设置cell height的方法是self.tableView.estimatedRowHeight
和代理方法-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
这两个东西,也提高了tableview的性能,当数据很多时,让它不是那么卡顿。
为什么?以前都是根据数据源的个数,刚开始就计算所有的高度。有了它之后呢,只有当滑动到这里的时候才计算。
next is -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
在这里我们计算的时候我们需要一个专门来计算高度的cell,为什么呢,因为计算方法是view
的一个实例方法在此方法里面。而且在-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
方法里,cell的重用失效了···,这个很奇怪哈。
我们可以定义一个static 的cell来,使用它的实例方法[cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]
计算size,
在此之前调用一下更新约束的方法[cell layoutIfNeeded];
让计算更可靠点。
不过这里有个注意点,在有多行label的时候,需要指定它的宽度像这样self.userComment.preferredMaxLayoutWidth = 293;
否则它是不会换行的。
这样计算下来高度还是不对,为什么呢?
高度还差1
,因为你计算的时contentview
的高度,cell
的实际高度比contentview
的高度还高1
哦。
这种方法和以前相比已经方便很多了,但是,计算的速度没有手算的快,所以如果考虑不到位,卡顿现象就会很明显。
上面的方法需要同学对约束掌握熟练,保证上下左右都有约束支撑。特别是在视图很多的时候,约束很可能出现冲突,大家要灵活的运用priority
、content hugging
、content compression
,这些属性解决冲突
有不足的地方请同学补充,谢谢。需要demo的同学留下地址
Tip
因为UILabel和UITextView,都存在多行展示的问题,所以要下知道最大宽度,这里我们可以这样
- (void)layoutSubviews
{
[super layoutSubviews];
myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
[super layoutSubviews];
}
第一次调用[super layoutSubviews]
是为了获得label现在的真实frame,第二次调用是为了更新布局。
网友评论