AutoLayout处理UITableView动态高度
我们经常会遇到UITableViewCell的高度要跟随内容而调整,在未引入AutoLayout之前,我们使用以下方法计算Label高度,然后heightForRowAtIndexPath中返回计算的高度,这种做法,真的很土很局限很不好,如果UILabel使用了CoreText或者UIKit进行了富文本不同字体的排版,它更是没办法,我还得分段来计算,总之各种麻烦。
- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(NSLineBreakMode)lineBreakMode NS_DEPRECATED_IOS(2_0, 7_0, "Use -boundingRectWithSize:options:attributes:context:"); // NSTextAlignment is not needed to determine size
本系列文章我们讨论的是AutoLayout,那iOS6引入AutoLayout之后,情况是否有所变化呢?当然!而且AutoLayout在iOS不断更新过程中,也在一起不断的优化,以方便开发者进行布局。说实话,跟很多开发者一样,我目前也并不是特别喜欢AutoLayout,有一些不可控的因素,布局并没有完全掌握在自己手上,需要依赖系统根据约束进行调整,这让保守的开发人员很没有安全感。不废话了,我们还是进入到正题。
我们直接拿一个现实的需求来进行讨论,如下图,我们需要构建一个页面,上面部分显示我们预约保养的基本信息,下面部分显示该门店目前提供的优惠券列表,这种需求最简单的做法就是直接用两种UITableViewCell,下面的部分的UITableViewCell要简单一些,高度固定,而上面部分的UITableViewCell的内容有很多不确定的内容,比如用户预约保养选择的项目,门店的名称地址,这些UILabel的高度都不确定,所以导致上面部分的UITableViewCell的高度需要动态调整,这是一个比较典型的实例,我们一起来看一下如何解决。
一、建立合理的约束
我们先建立自定义Cell: AppointmentedInfoCell (创建XIB)。 然后设置合理的约束条件,什么是合理的约束条件,一方面我们需要按前面讲到的设置正确的约束条件,另一方面我的意思主要是控件的compression resistance 和 hugging constraints ,在IB中如下图:
我们知道在Autolayout中,我们的UILabel,UIButton等控件都有了内建大小(intrinsic content size),就是说控件的大小会根据内容进行自动调整,可以将这些控件的大小和ScrollView的bounds和contentSize进行对比,意思有点类似,只不过UILabel,UIButton这些控件并不像Scrollview一样可以在bounds不等于contentSize的情况下进行滚动查看内容。 在这里为了使用UILabel的内建大小,我们要保持compression resistance 和 hugging constraints 的垂直方向优先级没有被更高的优先级所覆盖,比如更改了UILabel内建大小的优先级(priority),并设置了UILabel的高度约束的优先级高于内建大小的优先级,那内建大小自然就不起作用了,就会以高优先级为准.
一方面我们确保了AppointmentedInfoCell中的控件,目前全是UILabel,其内建大小垂直方向优先级为最高的1000。 光这个还不够,我们还要确保内建大小的边缘跟随内建大小一起变化,从而保证我们的内建大小可以起作用,说白了,就是要求contentView中的子控件建立与superView的约束,我们先建立第一个UILabel(姓名、电话)与superview top 的间距约束,然后依次往下建立控件之间推荐间距的约束,左边同列控件建立左部对齐约束,右边同行内容的建立顶部对齐约束,垂直方向的间距约束,最底部的”预约结果Label”建立与superview bottom的间距约束。
特别提醒:与contentView的四边间距约束很重要,有了4个与contentView的边缘约束,才能保证contentView的大小跟随其subviews变化。
上面这些就是建立合理的约束条件,这里随便提醒一下,UILabel在IB中布局的大小如果跟内容计算出来的不一致就会有警告,比如UILabel长度为200,目前的内容为2个14号字的长度,那UILabel就会有警告,对于这种警告,你需要忍住你的强迫症。
二、计算行高
这一步在iOS7与iOS8上面就有所不同了,我们先来看最新的iOS8。
1、iOS8:
从iOS8开始引入了UITableViewCell的高度的自适应功能,在iOS8之前实现很麻烦的功能,iOS8以后就不需要自己动手去做了,稍后我们会看一下iOS7下面如何做。
//打开tableview的高度估算功能
_iTableView.rowHeight = UITableViewAutomaticDimension;
_iTableView.estimatedRowHeight = 70.0;
estimatedRowHeight必须设置为大于0,为了画面的过度顺畅,保证UITableview的高度变化不至于导致UITableview的大范围滚动而影响了用户视觉体验,我们用一个预估的平均值,这也就是所谓的预估值。estimatedRowHeight并不是最终的行高,当一个Cell需要显示的时候,会精确计算实际的行高,contentView的宽度就是UITableview的宽度减去Section Index,accessoryView等的宽度,contentView的高度则会自动根据其子视图的约束关系计算,当此精确值被计算出过后,estimatedRowHeight、tableview的contentSize,bounds,这些都会跟随更新。
estimatedRowHeight每一行都会使用此值用于该行的预估值,进而初步预估UITableView的contentSize。如果UITableView每行内容变化很大,行高差别很大,那我们可以使用以下方法为每一行设置各不相同的预估值。也就是说有通用值,也有个性值。
- (void)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath;
OK,预估值只是一个插曲,我们来看精确值,在iOS8过后,我们只需简单的激活预估值,并在heightForRowAtIndexPath中返回UITableViewAutomaticDimension即可。
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (IS_IOS8_OR_ABOVE) {
return UITableViewAutomaticDimension;
}
}
2、iOS7:
UITableViewCell的contentView的高度自适应是iOS8中加入的,iOS7就只能自己计算了,所以我们来看一下iOS7下如何处理的。
//NIB注册,获取自定义UITableView实例的方式有很多种,这里随便用一种
UINib *cellNib = [UINib nibWithNibName:@"AppointmentedInfoCell" bundle:nil];
[self.tableView registerNib:cellNib forCellReuseIdentifier:@"AppointmentedInfoCell"]; //先创建一个基本的Cell实例,我们后面cellForRowAtIndexPath 和 heightForRowAtIndexPath 都需要用,由于UITableView的加载过程是先计算出所有的行高,再对每行进行渲染的,即 heightForRowAtIndexPath是先调用的,所以这里的baseCell就是一个离屏控件,用于辅助计算高度的,而后面也可以直接使用其用于每行内容的更新,每种类型的Cell只需要一个即可,这样我们的离屏内存并不会浪费。 _baseCell = [cellNib instantiateWithOwner:nil options:nil][]; //更新Cell内容
- (void)configureCell:(AppointmentedInfoCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
//更新contentView的子控件
} //
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
AppointmentedInfoCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AppointmentedInfoCell" forIndexPath:indexPath];
[self configureCell:cell atIndexPath:indexPath];
return cell;
} //
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
[self configureCell:_baseCell atIndexPath:indexPath];
[_baseCell layoutSubviews];
CGFloat height = [_baseCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return height + ;//由于分割线,所以contentView的高度要小于row 一个像素。
}
OK,到这里,我们基本上就掌握了AutoLayout的UITableViewCell的动态高度的处理,关键点就是systemLayoutSizeFittingSize的使用,希望本篇能够帮助你更好的理解AutoLayout以及UITableView在iOS8新增的布局处理。
AutoLayout处理UITableView动态高度的更多相关文章
- AutoLayout深入浅出五[UITableView动态高度]
本文转载至 http://grayluo.github.io//WeiFocusIo/autolayout/2015/02/01/autolayout5/ 我们经常会遇到UITableViewCell ...
- 使用Autolayout xib实现动态高度的TableViewCell
http://my.oschina.net/u/2360693/blog/481236?p={{totalPage}} 创建Xib文件 首先将Cell做好布局,调整到满意的位置和宽度,然后开始做Aut ...
- iOS开发——使用Autolayout生成动态高度的TableViewCell单元格
步骤一.TableViewCell中使用Autolayout 要点:Cell的高度必须在Constraints中指明,但不能定死,需要让内部由内容决定高度的View决定动态高度. 如UILabel设置 ...
- swift 版本 UItableViewCell的动态高度补足
用swift的朋友们很多都是从ios8开发了, 其中针对table cell高度自动计算的 UITableViewAutomaticDimension 异常好用,但好像只对uilabel对象有效 ...
- soui中,列表控件动态高度的使用注意
1.listview的模板template中,需要增加defHeight属性,即默认高度,同时,不能出现itemHeight属性,否则动态高度会失效 2.数据适配器中,重写getViewDesired ...
- UITableView动态存放、重用机制
一.UITableView动态存放 #import "ViewController.h"@interface ViewController ()<UITableViewDel ...
- css中height 100vh的应用场景,动态高度百分比布局,浏览器视区大小单位
css中height 100vh的应用场景,动态高度百分比布局,浏览器视区大小单位 height:100vh 一些只能vw, vh才能完成的应用场景: 1. 场景之:元素的尺寸限制 vw vh 主要是 ...
- 精简计算UITableView文本高度
精简计算UITableView文本高度 本人视频教程系类 iOS中CALayer的使用 最终效果: 核心源码(计算文本高度的类) NSString+StringHeight.h 与 NSStrin ...
- autoHeight # 动态高度添加 用 window.addEventListener('resize', function () {
动态高度添加 用 window.addEventListener('resize', function () { mounted () { this.init() window.addEventLis ...
随机推荐
- MySQL变更之:Online DDL 和 PT-OSC 该选谁?
参考: http://www.fromdual.ch/online-ddl_vs_pt-online-schema-change 在MySQL 5.6版本以前,最昂贵的数据库操作之一就是执行数据定义语 ...
- Spark系列视频
大数据生态圈很大,很多开发者都仅仅接触到某个单一产品. Spark 是近年来比较流行的大数据计算框架,系统.平台要想用好Spark 这个产品,需要用到很多的产品. 本视频系列主要是为准备入坑大数据的童 ...
- JSF 与 struts2
http://suhuanzheng7784877.iteye.com/blog/1041411
- JS高级学习历程-15
昨天内容回顾 面向对象的私有成员.静态成员 私有成员:在构造函数里边定义局部变量,就是私有成员. 静态成员:在js里边,函数就是对象,可以通过给函数对象声明成员方式声明静态成员. 原型继承 关键字:p ...
- K.河北美食
链接:https://ac.nowcoder.com/acm/contest/903/K 题意: icebound最喜欢吃河北菜,于是他想要大厨做一桌河北菜宴请宾客.icebound购买了一些食材,并 ...
- 类成员函数的重载、覆盖和隐藏区别 (C++)
这是本人第一次写博客,主要是想记录自己的学习过程.心得体会,一是可以方便以后回顾相关知识,二是可以与大家相互学习交流. 关于C++中类成员函数的重载.覆盖和隐藏区别,第一次看到这个问题是在准备找工作的 ...
- 《深入理解java虚拟机》笔记(7)JVM调优(分代垃圾收集器)
以下配置主要针对分代垃圾回收算法而言. 一.堆大小设置 年轻代的设置很关键 JVM中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制:系统的可用虚拟内存限制:系统的可用 ...
- 朱晔的互联网架构实践心得S2E7:漫谈平台架构的工作(基础架构、基础服务、基础平台、基础中间件等等)
前言 程序开发毕竟还不是搬砖这种无脑体力劳动,需要事先有标准,有架构,有设计,绝对不是新公司今天创立,明天就可以开始编码的.其实很多公司在起步的时候没有财力和资源建设独立的基础架构或平台架构部门,甚至 ...
- Java语法基础(2)
一.变量与常量 1.标识符与关键字 (1). 标识符 标识符可以简单的理解为一个名字,用来标识类名.变量名.方法名.数组名.文件名的有效字符序列.如图所示. Java语言规定标识符由任意顺序的字母.下 ...
- I/O————流
流的关系图 缓冲流分为字节和字符缓冲流(图中是经常用的搭配,PrintWrite与BufferedWrite都继承java.io.Write) 字节缓冲流为: BufferedInputStream— ...