在tableview在使用autolayout,自适应cell的高度(iOS7+)
一、概述 1、声明NSDictinary *offscreenCell
a. 用来存储每种类型cell的一个对象实例 b. 此dictionary的key为每种类型cell的reuse identifier,value为该类型cell的一个对象实例
2、cell的注册
a. 使用tableview的registerClass方法来进行cell的注册 b. 若有多种类型的cell,则要用registerClass注册多个cell
3、初始化cell,并返回cell高度
a. 在heightForRowAtIndexPath方法里,进行cell的初始化 b. 使用systemLayoutSizeFittingSize方法获取cell的高度
4、cell赋值
在cellForRowAtIndexPath方法里,进行cell的赋值
5、使用autolayout对需要的控件进行布局
有两种方式: a. 使用xib b. 重写自定义cell类里的updateConstraints方法,手动用代码进行布局
注:本文使用Masonry 进行布局
6、通知系统进行布局
在自定义的cell类里的layoutSubviews方法,调用相关方法通知系统进行布局
二、关键点 1、autolayout要设置正确,如果不正确,systemLayoutSizeFittingSize方法计算出来的高度是0
三、示例代码
假设有两种类型的cell,先自定义两个cell类 分别命名为AutoResizeCell SecondResizeCellreuse identify分别为autoResizeCellId secondResizeCellId
1、在controller里的viewDidLoad
1 2 3 4 5 6 7 8 9 10 /////////////// step: 1 /////////////// self.offscreenCell = [NSMutableDictionary dictionary]; /////////////// step: 1 /////////////// /////////////// step: 2 /////////////// [self.myTableView registerClass:[AutoResizeCell class] forCellReuseIdentifier:autoResizeCellId]; [self.myTableView registerClass:[SecondResizeCell class] forCellReuseIdentifier:secondResizeCellId]; // Setting the estimated row height prevents the table view from calling tableView:heightForRowAtIndexPath: for every row in the table on first load; // it will only be called as cells are about to scroll onscreen. This is a major performance optimization.self.myTableView.estimatedRowHeight = UITableViewAutomaticDimension; // iOS7+ /////////////// step: 2 ///////////////
2、在controller里的heightForRowAtIndexPath
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 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { /////////////// step: 3 /////////////// NSDictionary *aDict = [self getRowDataDictInSection:indexPath.section row:indexPath.row]; BOOL hasAvatar = [[aDict objectForKey:HAS_AVATAR] boolValue]; NSString *reuseIdentifier = (hasAvatar ? secondResizeCellId : autoResizeCellId); UITableViewCell *cell = [self.offscreenCell objectForKey:reuseIdentifier]; if (!cell) { if (hasAvatar) { cell = [[SecondResizeCell alloc] init]; } else { cell = [[AutoResizeCell alloc] init]; } [self.offscreenCell setObject:cell forKey:reuseIdentifier]; } if (hasAvatar) { [(SecondResizeCell*)cell initModel:aDict]; } else { [(AutoResizeCell*)cell initModel:aDict]; } cell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(tableView.bounds), CGRectGetHeight(cell.bounds)); [cell setNeedsLayout]; [cell layoutIfNeeded]; CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; height += 1; /////////////// step: 3 /////////////// return height; }
3、在controller里的cellForRowAtIndexPath
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { /////////////// step: 4 /////////////// NSDictionary *aDict = [self getRowDataDictInSection:indexPath.section row:indexPath.row]; BOOL hasAvatar = [[aDict objectForKey:HAS_AVATAR] boolValue]; NSString *reuseIdentifier = (hasAvatar ? secondResizeCellId : autoResizeCellId); AutoResizeCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier]; if (hasAvatar) { [(SecondResizeCell*)cell initModel:aDict]; } else { [(AutoResizeCell*)cell initModel:aDict]; } /////////////// step: 4 /////////////// return cell; }
4、在自定义cell类的initModel
1 2 3 4 5 6 7 8 9 10 11 - (void)initModel:(id)model { self.titleLabel.text = [model objectForKey:@"title"]; self.bodyLabel.text = [model objectForKey:@"content"]; // Make sure the constraints have been added to this cell, since it may have just been created from scratch /////////////// step: 4 /////////////// [self setNeedsUpdateConstraints]; [self updateConstraintsIfNeeded]; /////////////// step: 4 /////////////// }
5、在自定义cell类的updateConstraints
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 - (void)updateConstraints { /////////////// step: 5 /////////////// if (!self.didSetupConstraints) { // titleLabel [_titleLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.top.mas_equalTo(kLabelVerticalInsets); make.left.mas_equalTo(kLabelHorizontalInsets); make.right.mas_equalTo(-kLabelHorizontalInsets); // need }]; // bodyLabel [_bodyLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.top.mas_equalTo(_titleLabel.mas_bottom).with.offset(kLabelVerticalInsets); make.left.mas_equalTo(_titleLabel.mas_left); make.bottom.mas_equalTo(-kLabelVerticalInsets); // need make.right.mas_equalTo(_titleLabel.mas_right); }]; self.didSetupConstraints = YES; } [super updateConstraints]; /////////////// step: 5 /////////////// }
6、在自定义cell类的layoutSubviews
1 2 3 4 5 6 7 8 9 10 11 - (void)layoutSubviews { [super layoutSubviews]; /////////////// step: 6 /////////////// [self.contentView setNeedsLayout]; [self.contentView layoutIfNeeded]; _titleLabel.preferredMaxLayoutWidth = CGRectGetWidth(_titleLabel.frame); _bodyLabel.preferredMaxLayoutWidth = CGRectGetWidth(_bodyLabel.frame); /////////////// step: 6 /////////////// }
四、完整demo代码 点击跳转到github
五、autolayout相关资料 1)开始iOS 7中自动布局教程(上下部分) 1、http://www.cocoachina.com/industry/20131203/7462.html 2、http://www.cnblogs.com/zer0Black/p/3977288.html
2)Masonry说明: 官方:https://github.com/Masonry/Masonry 第三方:http://adad184.com/2014/09/28/use-masonry-to-quick-solve-autolayout/
3)tableview动态计算cell高度 1、 http://www.ifun.cc/blog/2014/02/21/dong-tai-ji-suan-uitableviewcellgao-du-xiang-jie/ 2、http://www.devdiv.com/autolayout_uitableviewcell_-blog-21666-52543.html 3、http://www.tuicool.com/articles/FZN3q2 4、http://stackoverflow.com/questions/18746929/using-auto-layout-in-uitableview-for-dynamic-cell-layouts-variable-row-heights