转载自:http://blog.youkuaiyun.com/joonchen111/article/details/50193499
我们很多iOS开发者应该都用过autolayout , 如果用故事版和XIB的话非常好用,但是如果用纯代码的方式写的话就感觉这东西太啰嗦了,一点都不好用,还不如frame来得快,然而在公司项目中一般都是多人开发,因此还是以纯代码写的方式比较多;随着苹果大屏手机的推出,autolayout越来越势在必行了,然而我们却发现这东西以代码写的方式简直可以让人写到吐血,还好一个国外大神推出了一套封装好autolayout框架Masnory, Masonry是一个轻量级的布局框架 拥有自己的描述语法采用更优雅的链式语法封装自动布局简洁明了并具有高可读性而且同时支持 iOS和 Max OS X。(示例代码下载地址)
Masonry框架怎么学习我这里就不详细说了,网上一大堆,都很不错;使用Masonry很好用可以布局任何我们想要的结果,但是在计算cell高度方面确实遇到了一些小麻烦,我在网上找了很多资料,都不是很理想,我记得其中一个Masonry+FF什么的框架来计算cell高度,我擦好麻烦,我想不用这么啰嗦吧!于是乎自己搞了一个下午,搞出了一套简单的方法,供大家参考学习。交流群 519797474
效果图如下:
废话不多话 直接上代码
- #import "HomeViewController.h"
- #import "HomeViewCell.h"
- #import "HomeModel.h"
- @interface HomeViewController ()
- @property (nonatomic,strong) NSMutableArray *arr; //存放的我们自定义的数据
- @property (nonatomic,strong) NSMutableArray *arrModel; //存放的数据模型
- @property (nonatomic,strong) NSMutableDictionary *cellHeightCache; //缓存每一行的行高
- @end
- @implementation HomeViewController
- -(NSMutableArray *)arr
- {
- if(_arr==nil){
- _arr=[NSMutableArray array];
- [_arr addObject:@"高通与小米达成专利授权协议的主要影响在于小米的海外市场,因为在国内小米并不会遇到专利问题。然而,分析小米在海外遇到的问题会发现,这远不是签订一个专利协议能解决"];
- [_arr addObject:@"当年科比和乔丹的对决,那时的科比几乎无所不能,谁又会想到他会退役,说不定再过10年,我也就退役了。"];
- [_arr addObject:@"高通与小米达成专利授权协议的主要影响在于小米的海外市场,因为在国内小米并不会遇到专利问题。然而,分析小米在海外遇到的问题会发现,这远不是签订一个专利协议能解决"];
- [_arr addObject:@"hello 这是我的iOS学习群 519797474,欢迎加入"];
- [_arr addObject:@"佛堂中,大师正在对弟子讲话:“为师为你们所起之名并非随随便便,而是为师对你们的期望,你们懂了吗?”众弟子都回答懂了。只有一名弟子默然不语。大师见状,问那名弟子道:“圆寂,你为什么不说话?"];
- [_arr addObject:@"最后这个例子是老例子了最后这个例子是老例子了,我想给大家看看其实Masonry做动画也和其他的Autolayout方法一样,但是添加约束的代码却非常的少最后这个例子是老例子了,我想给大家看看其实Masonry做动画也和其他的Autolayout方法一样,但是添加约束的代码却非常的少最后这个例子是老例子了,我想给大家看看其实Masonry做动画也和其他的Autolayout方法一样,但是添加约束的代码却非常的少最后这个例子是老例子了,我想给大家看看其实Masonry做动画也和其他的Autolayout方法一样,但是添加约束的代码却非常的少最后这个例子是老例子了,我想给大家看看其实Masonry做动画也和其他的Autolayout方法一样,但是添加约束的代码却非常的少最后这个例子是老例子了,我想给大家看看其实Masonry做动画也和其他的Autolayout方法一样,但是添加约束的代码却非常的少"];
- [_arr addObject:@"今天和老婆吵架,吵到激烈的时候,我突然觉得我一个大男人为什么要和一个女人一般见识呢?何况还是自己的老婆!当时我就跟老婆道了歉,老婆挺高兴的.道完歉,她哥哥把菜刀放下了,她弟弟把铁锹也放下了,她妹妹拽着我头发的手也松开了,妹夫手里的擀面杖也扔地下了,老丈人也把砖头丢开了;"];
- [_arr addObject:@"昨天去一家工厂面试监工,给出的工资太低,简直不能忍。最后跟主管去车间看了看,我觉得工资只是数字而已,关键是学习的机会,所以留下来了。"];
- [_arr addObject:@"大家好,我是他主治医生。请原谅他,他因为神经病引起的并发症迷恋上了装逼,去年高考 ,他差一点就上清华了,现在想来依然倍感惋惜,清华分数695,他考了69.5,就差那么一点。巨大的打击彻底粉碎了他对未来的憧憬,整日在家自暴自弃专研怎么装逼,终成为新一代装逼大师,将装逼 方法研究的出神入化,各种装逼方法,无死角装逼,终于横空出世…。你看,他又在装逼......."];
- [_arr addObject:@"高通与小米达成专利授权协议的主要影响在于小米的海外市场,因为在国内小米并不会遇到专利问题。然而,分析小米在海外遇到的问题会发现,这远不是签订一个专利协议能解决,周鸿祎的当别人都这么做的时候,我们换一种方式去做;和雷军的打败一种东西的一定是更新的东西而不是简单的复制。越想越觉得他们的理念异曲同工周鸿祎的当别人都这么做的时候,我们换一种方式去做;和雷军的打败一种东西的一定是更新的东西而不是简单的复制。越想越觉得他们的理念异曲同工周鸿祎的当别人都这么做的时候,我们换一种方式去做;和雷军的打败一种东西的一定是更新的东西而不是简单的复制。越想越觉得他们的理念异曲同工周鸿祎的当别人都这么做的时候,我们换一种方式去做;和雷军的打败一种东西的一定是更新的东西而不是简单的复制。越想越觉得他们的理念异曲同工周鸿祎的当别人都这么做的时候,我们换一种方式去做;和雷军的打败一种东西的一定是更新的东西而不是简单的复制。越想越觉得他们的理念异曲同工周鸿祎的当别人都这么做的时候,我们换一种方式去做;和雷军的打败一种东西的一定是更新的东西而不是简单的复制。越想越觉得他们的理念异曲同工周鸿祎的当别人都这么做的时候,我们换一种方式去做;和雷军的打败一种东西的一定是更新的东西而不是简单的复制。越想越觉得他们的理念异曲同工周鸿祎的当别人都这么做的时候,我们换一种方式去做;和雷军的打败一种东西的一定是更新的东西而不是简单的复制。越想越觉得他们的理念异曲同工周鸿祎的当别人都这么做的时候,我们换一种方式去做;和雷军的打败一种东西的一定是更新的东西而不是简单的复制。越想越觉得他们的理念异曲同工周鸿祎的当别人都这么做的时候,我们换一种方式去做;和雷军的打败一种东西的一定是更新的东西而不是简单的复制。越想越觉得他们的理念异曲同工"];
- [_arr addObject:@"很多时候我们过高估计了机遇的力量,低估了规划的重要性,不明确的乐观主义者只知道未来越来越好,却不知道究竟多好,因此不去制定具体计划。他想在未来获利,但是却认为没有必要制定具体规划。"];
- [_arr addObject:@"hello 这是我的iOS学习群 519797474,欢迎加入"];
- [_arr addObject:@"高通与小米达成专利授权协议的主要影响在于小米的海外市场,因为在国内小米并不会遇到专利问题。然而,分析小米在海外遇到的问题会发现,这远不是签订一个专利协议能解决"];
- for(int i=0;i<_arr.count;i++){
- HomeModel *m=[[HomeModel alloc]init];
- m.icon=[NSString stringWithFormat:@"%i",i%9];
- m.content=_arr[i];
- //把模型那存到模型数组中
- [self.arrModel addObject:m];
- }
- }
- return _arr;
- }
- -(NSMutableDictionary *)cellHeightCache
- {
- if(!_cellHeightCache){
- _cellHeightCache = [NSMutableDictionary dictionary];
- }
- return _cellHeightCache;
- }
- -(NSMutableArray *)arrModel
- {
- if(_arrModel==nil){
- _arrModel=[NSMutableArray array];
- }
- return _arrModel;
- }
- - (void)viewDidLoad {
- [super viewDidLoad];
- self.tableView.separatorStyle=UITableViewCellSeparatorStyleNone;//去掉默认下划线
- self.tableView.estimatedRowHeight=200; //预估行高 可以提高性能
- self.tableView.rowHeight = 88;
- //注册表格单元
- [self.tableView registerClass:[HomeViewCell class] forCellReuseIdentifier:homeIndentifier];
- }
- /*
- 返回多少行
- */
- - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
- //因为是我们自定义的数据 所以 这里写arr而不是arrModel 因为只有这样才会调用arr的懒加载犯法
- return self.arr.count;
- }
- /*
- 返回表格单元
- */
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
- //取出模型
- HomeModel *model=self.arrModel[indexPath.row];
- HomeViewCell *cell = [tableView dequeueReusableCellWithIdentifier:homeIndentifier];
- //传递模型给cell
- cell.homeModel=model;
- return cell;
- }
- /*
- * 返回每一个表格单元的高度
- */
- -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- //第一种方法
- // HomeModel *homeModel = self.arrModel[indexPath.row];
- // return homeModel.cellHeight;
- //另一种实现方法
- id h = [self.cellHeightCache objectForKey:@(indexPath.row)];
- if(h){
- NSLog(@"%@",h);
- return [h floatValue];
- }
- //取出模型
- HomeModel *homeModel=self.arrModel[indexPath.row];
- HomeViewCell *cell = [tableView dequeueReusableCellWithIdentifier:homeIndentifier];
- //行高放入缓存
- CGFloat cellH = [cell rowHeightWithCellModel:homeModel];
- [self.cellHeightCache setObject:@(cellH) forKey:@(indexPath.row)];
- return cellH;
- }
- @end
下面是表格cell的代码 (视图类)
- #import <UIKit/UIKit.h>
- #import "Masonry.h"
- @class HomeModel;
- static NSString *homeIndentifier=@"homeCell";
- @interface HomeViewCell : UITableViewCell
- //数据模型
- @property (nonatomic,strong) HomeModel *homeModel;
- //我们最后得到cell的高度的方法
- -(CGFloat)rowHeightWithCellModel:(HomeModel *)homeModel;
- @end
- #import "HomeViewCell.h"
- #import "HomeModel.h"
- //头像的高度
- #define iconH 80
- #define iconW 100
- //间距
- #define marginW 10
- @interface HomeViewCell ()
- @property (nonatomic,weak) UIImageView *icon; //头像
- @property (nonatomic,weak) UILabel *content; //显示文本的label
- @property (nonatomic,weak) UIImageView *line; //下划线
- //定义一个contentLabel文本高度的属性
- @property (nonatomic,assign) CGFloat contentLabelH;
- @end
- @implementation HomeViewCell
- -(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
- {
- self=[super initWithStyle:style reuseIdentifier:reuseIdentifier];
- if(self){
- //1.添加子控件
- [self setupUI];
- }
- return self;
- }
- #pragma mark 添加子控件
- -(void)setupUI
- {
- //1.添加图片
- UIImageView *icon=[UIImageView new];
- icon.contentMode=UIViewContentModeScaleAspectFill;
- icon.clipsToBounds=YES;
- [self.contentView addSubview:icon];
- self.icon=icon;
- //2.添加label
- UILabel *content=[UILabel new];
- content.numberOfLines=0; //多行显示
- content.font=[UIFont systemFontOfSize:16];
- [self.contentView addSubview:content];
- self.content=content;
- //3.底部添加一条线
- UIImageView *line=[UIImageView new];
- line.backgroundColor=[UIColor grayColor];
- [self.contentView addSubview:line];
- self.line=line;
- //设置约束
- __weak __typeof(&*self)weakSelf = self;
- //1.设置图片的大小
- [self.icon mas_makeConstraints:^(MASConstraintMaker *make) {
- make.height.mas_equalTo(iconH); //头像的高度
- make.width.mas_equalTo(iconW); //头像的宽度
- make.top.equalTo(weakSelf.mas_top).offset(marginW) ; //距离顶部10的距离
- make.centerX.equalTo(weakSelf.mas_centerX); //头像的中心x和cell的中心x一样
- // make.centerY.equalTo(self.mas_centerY); 头像的中心y和cell的中心y一样
- }];
- //2.设置contentLabel
- [self.content mas_makeConstraints:^(MASConstraintMaker *make) {
- make.top.equalTo(weakSelf.icon.mas_bottom).offset(marginW); //文本距离头像底部10个间距
- make.left.equalTo(weakSelf.mas_left).offset(marginW); //文本距离左边的距离
- make.right.equalTo(weakSelf.mas_right).offset(-marginW); //文本距离右边的距离
- //文本高度 我们再得到模型的时候 在传递
- }];
- //3.设置下划线的大小
- [self.line mas_makeConstraints:^(MASConstraintMaker *make) {
- make.height.mas_equalTo(0.5);
- make.left.equalTo(weakSelf.mas_left).offset(0);
- make.right.equalTo(weakSelf.mas_right).offset(0);
- make.bottom.equalTo(weakSelf.mas_bottom).offset(-marginW); //下划线距离底部10的距离
- }];
- }
- //传递数据模型
- -(void)setHomeModel:(HomeModel *)homeModel
- {
- _homeModel=homeModel;
- self.icon.image=[UIImage imageNamed:homeModel.icon]; //头像
- self.content.text=homeModel.content; //文本内容
- }
- //在表格cell中 计算出高度
- -(CGFloat)rowHeightWithCellModel:(HomeModel *)homeModel
- {
- _homeModel=homeModel;
- __weak __typeof(&*self)weakSelf = self;
- //设置标签的高度
- [self.content mas_makeConstraints:^(MASConstraintMaker *make) {
- // weakSelf.contentLabelH 这个会调用下面的懒加载方法
- make.height.mas_equalTo(weakSelf.contentLabelH);
- }];
- // 2. 更新约束
- [self layoutIfNeeded];
- //3. 视图的最大 Y 值
- CGFloat h= CGRectGetMaxY(self.content.frame);
- return h+marginW; //最大的高度+10
- }
- /*
- * 懒加载的方法返回contentLabel的高度 (只会调用一次)
- */
- -(CGFloat)contentLabelH
- {
- if(!_contentLabelH){
- CGFloat h=[self.homeModel.content boundingRectWithSize:CGSizeMake(([UIScreen mainScreen].bounds.size.width)-2*marginW, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16]} context:nil].size.height;
- _contentLabelH=h+marginW; //内容距离底部下划线10的距离
- }
- return _contentLabelH;
- }
- @end
下面是数据模型 (HomeModel类)
- #import <UIKit/UIKit.h>
- @interface HomeModel : NSObject
- @property (nonatomic,copy) NSString *icon; //图片
- @property (nonatomic,copy) NSString *content; //内容的label
- //单元格的高度
- @property (nonatomic,assign) CGFloat cellHeight;
- @end
- #import "HomeModel.h"
- #import "HomeViewCell.h"
- @implementation HomeModel
- //惰性初始化是这样写的 只会加载一次,不会造成循环引用的性能问题
- -(CGFloat)cellHeight
- {
- //只在初始化的时候调用一次就Ok
- if(!_cellHeight){
- HomeViewCell *cell=[[HomeViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:homeIndentifier];
- NSLog(@"我要计算高度");
- // 调用cell的方法计算出高度
- _cellHeight=[cell rowHeightWithCellModel:self];
- }
- return _cellHeight;
- }
- @end
到这里我们整个计算cell高度的方法就完了,最重要的是我们要学会举一反三,学会这套思想,从而可以使用autolayout框架写出任何我们想要布局的代码,如果大家有什么疑问可以加入iOS大神群讨论 519797474 ( 示例代码下载 ) ( 更吊的开源项目 )

