在iOS开发中,iOS8.0以前tableview自适应行高是一个非常难处理的问题。本文讲述一下几种自适应行高的方法。
- iOS8.0+自适应行高的方式。
直接使用以下两行代码即可:
self.tableview.estimatedRowHeight = 44
//以下可以不写,默认值
self.tableView.rowHeight = UITableViewAutomaticDimension
- iOS7.0+适应行高的方式。
1.使用autolayout的方式加载视图,配合tableview中的heightForRowAt来实现。
2.配合tableview中的estimatedHeightForRowAt返回UITableViewAutomaticDimension来实现自适应行高。
下面我们来讲解工程。
本工程运用swift编写,入口是RootViewController。
我们定义全局常量文件:GlobalConst.swift,如下,存储当前需要的数据。
var contentAry:[String] = ["人生有三重境界,这三重境界可以用一段充满禅机的语言来说明,这段语言便是:看山是山,看水是水;看山不是山,看水不是水;看山还是山,看水还是水","这就是说一个人的人生之初纯洁无暇,初识世界,一切都是新鲜的,眼睛看见什么就是什么,人家告诉他这是山,他就认识了山,告诉他这是水,他就认识了水","随着年龄渐长,经历的世事渐多,就发现这个世界的问题了。这个世界的问题越来越多,越来越复杂,经常是黑白颠倒,是非混淆,无理走天下,有理寸步难行,好人无好报,恶人千年。进入这个阶段,热是激情的,不平的,忧虑的,疑问的,警惕的,复杂的。人不愿意再轻易地相信什么。人在这个时候看山也感慨,看水也叹息,借古讽今,指桑骂槐。山自然不再是单纯的山,水自然不再是单纯的水。一切的一切都是人的主观意志的载体,所谓好风凭借力,送我上青云。倘若留在人生的这一阶段,那就苦了这条命了。人就会在山望了那山高,不停地攀登,争强好胜,与人比较,怎么做人,如何处世,绞尽脑汁,机关算尽,永无满足的一天,因为这个世界原本就是一个圆的,人外还有人,天外还有天,循环往复,绿水常流。而人的生命是短暂的有限的,哪里能够去与永恒和无限计较呢?","许多人到了人生的第二重境界就到了人生的终点。追求一生,劳碌一生,心高气傲一生,最后发现自己并没有达到自己的理想,于是抱恨终生。但是有一些人通过自己的修炼,终于把自己提升到了第三重人生境界。茅塞顿开,回归自然。人在这时候便会专心致志做自己应该做的事情,不与旁人有任何计较。任你红尘滚滚,自有清风朗月。面对芜杂世俗之事,一笑了之,了了有何不了。这个时候的人看山又是山,看水又是水了。正是:人本是人,不必刻意去做人;世本是世,无须精心去处世;便也是真正的做人与处世了。"];
在RootVC中,我们使用Storyboard的方式,加载tableview,创建cell,通以下方法通向其他界面。
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//项目的名称
let namespace = Bundle.main.infoDictionary!["CFBundleExecutable"] as! String
//当前的类名
let curClassname = self.diffClass[Array(self.diffClass.keys)[indexPath.row]]!
switch indexPath.row {
case 0:
let iOS8VC = iOS8ViewController.storyboardInstance()
self.navigationController?.pushViewController(iOS8VC!, animated: true)
case 1:
let autoVC = AutoLayoutViewController.init()
self.navigationController?.pushViewController(autoVC, animated: true)
default:
return
}
}
iOS8VC是也是一个Storyboard的文件,作者在此前看过此篇文章,为了加以实践才运用了这个方式去加载。此文件里面创建了普通的tableview,并且运用
self.tableview.estimatedRowHeight = 44
直接让文件自适应成功。
接下来,为了适配iOS7+,作者新建了AutoLayoutViewController。
- 首先创建了AutoCell的xib,如下所示:
autocell.png
分别对上下左右进行了适配,并且设置宽度。在这里,我们需要注意的是要设置视图距离底部的距离,不然cell的高度永远为0。
接下来,我们重写了heightForRowAt的方法,如下
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// let cell = tableview.cellForRow(at: indexPath) as! AutoCell?
let cell = tableview.dequeueReusableCell(withIdentifier: "autocell") as! AutoCell?
cell?.cellLabel.text = contentAry[indexPath.row]
cell?.setNeedsUpdateConstraints()
cell?.updateConstraintsIfNeeded()
// CGFloat height = cell?.contentView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height
let height = (cell?.contentView.systemLayoutSizeFitting(UILayoutFittingCompressedSize).height)! as CGFloat
return height + 1;
}
其实此方法调用的时候,细心的程序员会发现,在tableview刚刚加载的时候,视图会调用此方法进行大量的运算,所以,如果数据过多,则必然会影响tableview的性能的问题。就像以前运用老一点的方法,用一个数组保存当前tableview需要刷新的内容,然后运用boundingRectWithSize 运算的时候,会有问题。并且,此方法是在func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
之前运行一次的,所以我们得小心运用,防止程序崩溃。
当然,还好苹果在iOS7+提供了
// 对可变cell 高度的估算
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {}
接口,让我们能够在程序运行之前估算当前cell的值而不进行运算。接下来我们只用调用以下方法,即可完成我们想要的结果。
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
此原理:首先利用autolayout来让cell里面的控件进行自己适配,然后在heightForRowAt上进行运算撑开cell。
当然,如果我们需要适配iOS6+的方法,我们则可以运用第三方框架来完成我们的需求,在github上有一个非常有效的框架FDTemplateLayoutCell。
关于优化,有两种方式,第一种就是尽量不要在heightForRowAt
里面使用大量的运算,最好是先用estimatedHeightForRowAt
或者tableview.estimatedRowHeight
来让tableview出现的时候先估算出高度,然后再进行渲染。第二种就是将当前计算的值给保存起来,防止下一次渲染的时候再进行运算。
Demo 地址
如有错误,欢迎指点,谢谢。