xib自适应高度

**

yongyinmg的专栏

    目录视图
    摘要视图
    订阅

CSDN博乐 举荐之美     公益活动,感谢你们     从零练就iOS高手实战班震撼来袭     新版极客头条上线,每天一大波干货    
使用Autolayout xib实现动态高度的TableViewCell
分类: ios autolayout 2014-09-23 15:48 5133人阅读 评论(0) 收藏 举报

目录(?)[+]
from:http://itony.me/381.html

最近又要做新功能了,虽然没有什么难点,只是获取后端XML数据显示到TableView,但是不是可以更简单快速的完成呢?原来Cell的动态高度一直都是通过sizeWithFont手动计算,潜意识觉得这应该不是最好的实现方式,但由于当时时间紧不允许尝试新技术,所以问题也就遗留了下来,这次又遇到了,时间充裕就解决下吧。

Autolayout是解决自适应frame问题的解决方案(iOS6.0就已经支持了,我现在才用= =#)。通过给视图元素设置合适的约束条件,内部会根据元素内容和限制条件计算出合适的尺寸显示。我们就不用自己手动写这些代码了。

文章步骤看上去有些复杂,真正做起来还是很快的,鼠标拖拽几下就能完成原来的手动计算高度部分代码,减少了很多重复性工作,也让代码看起来更加整洁。
创建Xib文件

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

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

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

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

Autolayout_Align

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

Autolayout_Pin

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

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

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

Autolayout_Constraint_Relation Config

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

Autolayout_Resolve Auto Layout Issues

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

Autolayout_ShortAction

大致就是这些了吧……

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

Autolayout_Example

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

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

使用了xib制作的Cell,那么在原来的项目代码中如何使用呢?看代码:
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,而在代码中手动处理,类似这样:

//内存优化
BBSPostContentCell*cell=[tableView
 dequeueReusableCellWithIdentifier:CellIdentifier];


if(cell==nil){


    cell=[[NSBundlemainBundle]
 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)。现在有两个办法解决:

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

思路很简单,我们告诉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部分代码,同上


        //.....


        returnheight;


    }else{


        //for
 iOS 5.x


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


        return81;


    }


}

完成了!

2013的最后一篇文章,元旦快乐!

    上一篇
    iOS开发常用国外网站清单
    下一篇
    iOS中代码支持多国语言切换的实现(Xcode5+iOS7)

猜你在找
    大数据编程语言:Java基础
    Apple Watch开发入门
    iOS8开发技术(Swift版):iOS基础知识
    Exchange 2013 管理
    网络赚钱靠谱项目推荐
    iOS开发笔记--UILabel的相关属性设置
    IOS通过NSCoding保存实体对象
    iOS开发的一些奇巧淫技
    UINavigationItem表示UINavigationBar中的控件
    将Lua嵌入IOS程序

准备好了么? 
跳
吧
             !
更多职位尽在 CSDN JOB
    iOS开发工程师
    上海彩亿信息技术有限公司
    |
    8-15K/月
    我要跳槽
    .NET开发工程师
    五八同城信息技术有限公司
    |
    20-40K/月
    我要跳槽
    php-百度 知识搜索部
    百度在线网络技术(北京)有限公司
    |
    15-30K/月
    我要跳槽
    靠谱公司呼唤靠谱Java牛人
    宜宝康健网络科技有限公司
    |
    12-24K/月
    我要跳槽

查看评论

  暂无评论

发表评论

    用 户 名:
    cjckkk

    评论内容:
    插入代码



* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
核心技术类目
全部主题 Hadoop AWS 移动游戏 Java Android iOS Swift 智能硬件 Docker OpenStack VPN Spark ERP IE10 Eclipse CRM JavaScript 数据库 Ubuntu NFC WAP jQuery BI HTML5 Spring Apache .NET API HTML SDK IIS Fedora XML LBS Unity Splashtop UML components Windows Mobile Rails QEMU KDE Cassandra CloudStack FTC coremail OPhone CouchBase 云计算 iOS6 Rackspace Web App SpringSide Maemo Compuware 大数据 aptech Perl Tornado Ruby Hibernate ThinkPHP HBase Pure Solr Angular Cloud Foundry Redis Scala Django Bootstrap

    个人资料

    [访问我的空间]
    yongyinmg
        访问:342679次
        积分:4002
        等级:
        排名:第3583名
        原创:11篇
        转载:281篇
        译文:0篇
        评论:63条

    文章搜索

    文章分类

    Ios(262)
    ios动画(36)
    ios8(13)
    ios autolayout(22)
    swift(9)
    iphone6适配(3)

    文章存档

    201505月(4)
    201504月(1)
    201503月(5)
    201502月(3)
    201501月(4)
    展开

    阅读排行 

    关于IOS的Autolayout特性的理解以及使用(18889)
    初探 iOS8 中的 Size Class(15550)
    iOS开发技巧(系列十五:autolayout自动布局)(11412)
    发布iOS应用(xcode5)到App Store(苹果商店) 详细解析(10279)
    iPhone 6 / 6 Plus 设计·适配方案(10160)
    iOS8 定位新增功能(9720)
    Xcode6的新特性、iPhone6和iPhone6Plus的适配,xcode6iphone6(9517)
    百度天气预报接口(8011)
    iOS8 Today 实现Clips widget(5234)
    使用Autolayout xib实现动态高度的TableViewCell(5115)

    评论排行

    iOS8 Today 实现Clips widget(12)
    初探 iOS8 中的 Size Class(8)
    发布iOS应用(xcode5)到App Store(苹果商店) 详细解析(6)
    Reveal查看任意app的高级技巧(4)
    关于IOS的Autolayout特性的理解以及使用(3)
    Reveal:分析iOS UI的利器(3)
    iOS8 定位新增功能(3)
    Responder Chain(ios事件传递)(3)
    Xcode6的新特性、iPhone6和iPhone6Plus的适配,xcode6iphone6(2)
    [iOS] 初探 iOS8 中的 Size Class(2)

    推荐文章

    最新评论

    CoreMotion框架-iOS设备的核心运动

    tanghaitao000: 请问大神做过实际的测试么?最近在做室内导航,不知道真机误差怎样
    iOS8 Today 实现Clips widget

    chenyixiu: 你好,怎么点击完widget跳进程序的指定界面呢?我现在只知道点击开启宿主程序。。。
    iOS8 Today 实现Clips widget

    chenyixiu: 你好,怎么点击完widget跳进程序的指定界面呢?我现在只知道点击开启宿主程序。。。
    用UIImagePickerViewController自定义相机界面

    在路上奋斗: 完整代码在哪里下载了 楼主?谢谢了 急着参考了
    用UIImagePickerViewController自定义相机界面

    deally: 完整的代码可以哪里下载
    willMoveToParentViewController和didMoveToParentViewController

    authorware310: 大神你好,又学习到了,多么深刻的领悟!
    willMoveToParentViewController和didMoveToParentViewController

    qq_25371283: 大神牛逼
    iOS8 Today 实现Clips widget

    yongyinmg: @humingtao2013:sorry 我加一下
    iOS8 Today 实现Clips widget

    MT_Hu-Struggle: .........大哥,你转载文章,起码加上转载链接吧
    制作动态及静态Framework

    NSObject_: 请问一下,自己制作的动态库运用到应用中是不是不能通过苹果公司审核啊?

    公司简介
    |
    招贤纳士
    |
    广告服务
    |
    银行汇款帐号
    |
    联系方式
    |
    版权声明
    |
    法律顾问
    |
    问题报告
    |
    合作伙伴
    |
    论坛反馈
    网站客服
    杂志客服
    微博客服
    webmaster@csdn.net
    400-600-2320|北京创新乐知信息技术有限公司 版权所有|江苏乐知网络技术有限公司 提供商务支持
    京 ICP 证 070598|Copyright © 1999-2014, CSDN.NET, All Rights Reserved 
    GongshangLogo

**
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于UITableViewCell中包含WebView的自适应高度问题,一般的解决方案是在webViewDidFinishLoad方法中计算WebView的高度,并更新UITableViewCell的高度。但是这种方法有时会出现计算不准确的情况,以及性能问题。 最新的解决方案是使用iOS 11中引入的UITableViewAutomaticDimension,结合约束自动布局来实现UITableViewCell的自适应高度。具体步骤如下: 1. 在Storyboard或XIB中,设置UITableViewCell的约束,包括WebView的顶部、底部、左右两侧的约束,并将WebView的高度设置为大于等于0的值(可以是一个较小的值,比如10)。 2. 在tableView(_:cellForRowAt:)方法中,设置WebView的代理为当前的UITableViewCell,并在webView(_:didFinish:)方法中更新UITableViewCell的高度: ```swift func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { // 计算WebView的内容高度 webView.evaluateJavaScript("document.readyState") { (result, error) in if result != nil { webView.evaluateJavaScript("document.body.offsetHeight", completionHandler: { (height, error) in if let height = height as? CGFloat { // 更新UITableViewCell的高度 self.heightConstraint.constant = height self.setNeedsUpdateConstraints() self.updateConstraintsIfNeeded() self.layoutIfNeeded() self.delegate?.didUpdateHeight() } }) } } } ``` 3. 在tableView(_:estimatedHeightForRowAt:)方法中,返回一个估算的高度(可以是一个较小的值,比如100): ```swift func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { return 100 } ``` 4. 在tableView(_:heightForRowAt:)方法中,返回UITableViewAutomaticDimension: ```swift func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return UITableViewAutomaticDimension } ``` 注意:在使用约束自动布局的情况下,需要保证UITableViewCell的高度约束是完整的,即顶部和底部都有约束,否则自适应高度可能会出现问题。同时,在更新UITableViewCell的高度时,需要调用setNeedsUpdateConstraints、updateConstraintsIfNeeded和layoutIfNeeded方法,以保证约束的更新及时生效。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值