关于Xib使用AutoLayout动态设置cell高度

最近又要做新功能了,虽然没有什么难点,只是获取后端XML数据显示到TableView,但是不是可以更简单快速的完成呢?原来Cell的动态高度一直都是通过sizeWithFont手动计算,潜意识觉得这应该不是最好的实现方式,但由于当时时间紧不允许尝试新技术,所以问题也就遗留了下来,这次又遇到了,时间充裕就解决下吧。 Autolayout是解决自适应frame问题的解决方案(iOS6.0就已经支持了,我现在才用=
=#)。通过给视图元素设置合适的约束条件,内部会根据元素内容和限制条件计算出合适的尺寸显示。我们就不用自己手动写这些代码了。 文章步骤看上去有些复杂,真正做起来还是很快...

创建Xib文件

首先将Cell做好布局,调整到满意的位置和宽度,然后开始做Autolayout设定。

Autolayout操作方式有两种,一种是选择目标后,使用右下角的工具栏;另一种是直接使用右键拖拽目标,在弹出的菜单中选择限制项。当选择的目标比较小的时候,可以打开左侧的菜单,在这里做拖拽操作一样是可以的。个人感觉后者更方便一些。

开始之前,先来介绍下使用的基本工具吧。

第一个按钮是和对齐有关的,就是控制多个元素(Lable, Button等)的统一约束。例如我们需要让标题和内容按照左,就选择标题和内容元素,选择Leading Edges设置为5即可。

第二个按钮是和元素位置固定有关的限制条件,直接看图吧:

右侧能够看到当前选择元素限制条件的列表:

这里有两个参数,“Content Hugging Priority”和“Content Compression Resistance Priority”,感觉不太好理解,栈爆上找到一篇解释,讲的挺好的:Cocoa
Autolayout: content hugging vs content compression resistance priority

有时候想要一个元素的间距是一个动态值,例如距离右侧至少10pt(即>=10pt),那么可以在上图中点击右侧按钮(齿轮)进入详细设置:

第三个按钮是有关清除限制条件、根据限制更新视图大小的工具。个人比较常用的是清除限制条件,有时候设置错了很麻烦,直接清除掉重新来就行了。

上面这些就是常用到的一些限制条件了。个人觉得使用右键拖拽弹出的菜单选择更方便和直观一些,因为菜单中会根据拖拽内容动态显示可用项供我们选择,菜单如图

大致就是这些了吧……

我来谈谈自己的用法。总体上是从上到下,从左到右做约束限制。在这个例子中,就是设置标题->内容->发帖人这样的顺序。

  1. 设置标题的顶部和左侧距离,以及宽度(防止超出边界)。
  2. 设置内容的顶部(距离标题)和左侧距离,以及宽度。设置最大行数。
  3. 设置发帖人的顶部和左侧距离,以及高度。
  4. 设置发帖时间的顶部和左侧距离,距离右侧间距(防止内容过长)。
  5. 关键步骤,设置发帖人距离底部距离,如果不设置这个参数,那么下面代码计算的Cell高度会永远是0。

多试一试,如果有错误或者缺少限制,XCode会有提示。它报出的错误一般都是必须修正的,但它给的自动修正建议有时并不是我们想要的(正确的),想清楚再添加。

代码部分

使用了xib制作的Cell,那么在原来的项目代码中如何使用呢?看代码:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37


static NSString *CellIdentifier = @"CellIdentifier";

- (void)viewDidLoad

{

//注册TableView中用于复用的Cell

[self.tableView registerNib:[UINib nibWithNibName:@"BBSPostContentCell" bundle:nil] forCellReuseIdentifier:CellIdentifier];

//...

}

//关键方法,获取复用的Cell后模拟赋值,然后取得Cell高度

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

{

BBSPostContentCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

NSDictionary *dataSourceItem = [self.dataSource objectAtIndex:indexPath.row];

cell.titleLabel.text =  [dataSourceItem valueForKey:@"title"];

cell.contentLabel.text = [dataSourceItem valueForKey:@"body"];

[cell setNeedsUpdateConstraints];

[cell updateConstraintsIfNeeded];

CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

return height;

}

//在cellForRowAtIndexPath中,按照常规方法做赋值就行了

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

BBSPostContentCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

NSDictionary *dic = dataSource[indexPath.row];

cell.titleLabel.text = dic[@"title"];

cell.contentLabel.text = dic[@"body"];

return cell;

}

2014.1.2: 在测试时发现这部分的代码还存在一些性能问题(整个表视图在更新时会卡顿),我会稍后补上。

我在使用Instruments分析发现,heightForRowAtIndexPath中调用dequeueReusableCellWithIdentifier会占用很多CPU资源,因此我试着不使用registerNib方法注册复用Cell,而在代码中手动处理,类似这样:


1

2

3

4

5

6

7


BBSPostContentCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil) {

cell = [[NSBundle mainBundle] loadNibNamed:@"BBSPostContentCell" owner:self options:NULL][0];

NSLog(@"cell
loadNibNamed");

else {

NSLog(@"cell
dequeueReusableCellWithIdentifier");

}

这时我发现这里的Cell调用dequeueReusableCellWithIdentifier方法总是返回nil,因此每次都是从xib中加载,从而耗费了大量的资源。问题的原因我还不清楚,目前我的解决方法是,单独生成一个Cell用于在heightForRowAtIndexPath方法中计算高度。

其次,在[tableView reloadData]和[tableView insertRowsAtIndexPaths]时,底层会将所有行高重新计算,这个会占用大量的时间,因此我试着对行高做了缓存,暂时解决了这个问题。

关于兼容性问题

由于Autolayout只能在iOS6.0以上版本使用,而根据友盟统计,目前6.0以下的用户大概还有8%左右(2013.12)。现在有两个办法解决:

  1. 哥不在乎,放弃这些用户!(好霸气=。=)把项目的部署版本修改为6.0以上即可。
  2. 咳…咳…这个嘛,用户还是有必要支持的………恩,那我们来说说这个怎么兼容。

思路很简单,我们告诉XCode,6.0以上版本使用Autolayout,以下的旧版本不要使用这个就可以了。

将原xib文件inspector中选择”Interface Builder Document”->”Build for”->”iOS 6.0 and Later”,告诉XCode,这个xib在6.0以上设备编译。

将xib文件拷贝一份副本,命名为”xxx_iOS5.xib”,在inspector中选择”Project Deployment Target”,也就是说使用项目部署目标版本(即最低版本5.0),并取消”Use Autolayout”选项。

在代码中根据系统版本加载不同的xib文件:


1

2

3

4

5

6

7

8

9

10

11

12

13

14


#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)
\

([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)

#define IS_SUPPORT_AUTOLAYOUT   SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"6.0")

- (void)viewDidLoad

{

if (!IS_SUPPORT_AUTOLAYOUT) {

//for iOS 5.x

[self.tableView registerNib:[UINib nibWithNibName:@"BBSPostContentCell_iOS5" bundle:nil] forCellReuseIdentifier:CellIdentifier];

else {

[self.tableView registerNib:[UINib nibWithNibName:@"BBSPostContentCell" bundle:nil] forCellReuseIdentifier:CellIdentifier];

}

}

最后别忘了在高度计算时,区分下代码:


1

2

3

4

5

6

7

8

9

10

11

12


- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

{

if (IS_SUPPORT_AUTOLAYOUT) {

//Autolayout部分代码,同上

//.....

return height;

else {

//for iOS
5.x

//为了简单起见,就直接使用固定值了,当然如果你要自己为iOS5用户手动计算动态高度,也是可以的。

return 81;

}

}

完成了!

时间: 2024-11-06 07:16:33

关于Xib使用AutoLayout动态设置cell高度的相关文章

UITableView使用AutoLayout动态计算cell高度

UITableView几乎是每个app都需要用的控件,而cell高度自适应也是我们 需要掌握的,当然cell上面的控件也是有多种表现形式,今天小编讲解的是其中一种比较常见的:Auto Layout with UILabel in UITableViewCell. 话不多说,上教程. 首先我们创建一个Sigle View Application的项目,然后拖上一个UITableView到storyboard中,设置好代理并且设置好约束.约束这里就不做讲解了,可以到AutoLayout详解了 解一下

05---MVC模式下动态调整Cell高度三部曲

动态调整Cell高度三部曲 我们在做项目开发的过程中经常会遇到每一个cell的高度及cell的子控件的显示个数不同,以我最近开发的微格为例,讲解一下MVC模式动态的调整Cell宽高的三部曲 1>.自定义Cell,重写- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier方法 在此方法中添加所有的可能显示的子控件 子控件的frame通过构建的cellFrame模型进行设置

动态设置iframe高度

<%//动态设置iframe高度 %><script language="javascript" type="text/javascript">      function SetWinHeight(obj) {                              var win = obj;        if (document.getElementByIdx_x) {            if (win && !

iOS8下动态改变Cell高度以及iOS8的动态类型理解

在iOS8中,苹果给出了一个激动人心的特性,UITableView 的 Self Sizing Cells.对于开发者来说,这是一个很值得一试的特性,在iOS8以前,如果需要在UITableViewCell中展示动态的内容,必须每次计算内容所占高度,然后赋值给UITableView的height. iOS8中如何使用此特性呢?基本有三步: 针对自定义Cell进行Layout Constraints设置 设置estimatedRowHeight 这是UITableView的RowHeight为UI

ios 动态设置Cell的高度

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ self.mainTitle=[[UILabel alloc]init]; self.mainTitle.numberOfLines=0; self.mainTitle.font=[UIFont fontWithName:@"Hiragino Sans GB" size:14];

iOS 动态计算cell高度实用API

// Use the estimatedHeight methods to quickly calcuate guessed values which will allow for fast load times of the table. // If these methods are implemented, the above -tableView:heightForXXX calls will be deferred until views are ready to be display

ScrollView嵌套listview 时根据内容动态设置listview高度

public static void setListViewHeightBasedOnChilds(ListView listView){ ListAdapter listAdapter = listView.getAdapter(); if(listAdapter==null){ return; } int totalHeight=0; int totalDividerHeight=0; for(int i = 0;i<listAdapter.getCount();i++){ View lis

scrollview嵌套listview时 动态设置listview高度

public class GetListViewHeight { public static void setListViewHeightBasedOnChildren(ListView listView) { ListAdapter listAdapter = listView.getAdapter(); if (listAdapter == null) { // pre-condition return; } int totalHeight = 0; for (int i = 0; i <

iOS开发动态计算cell的高度

在iOS开发过程中,我们经常会用到UITableView, 谈到UITableView当然少不了UITableViewCell.那么有时候我们就会有疑惑,怎么样才能让cell的高度根据文字的大小多少,以及照片的高度来动态设计呢? 下面我们来看一下,到底怎么做才能让cell的高度动态变化,让界面看起来更美观协调一些呢? //动态设置cell的高度 + (CGFloat)heightForRowWithModel:(PhotoInfo *)photoInfo { //1.图片的高度 //让图片等比例