复杂cell的高度计算
- 实现了多行文字的自适应
- 实现了图文混排的自适应
在我的日常开发中经常会遇到cell内容比较复杂的情况,复杂的cell势必会有cell高度不相同的情况,这种需求往往是比较蛋疼的。但是没关系只要掌握了其中的原理剩下的就只是体力活了。本文采用传统方式纯代码布局来计算cell的高度值,如果精力允许下篇介绍AutoLayout自动布局下的cell高度的计算。
ViewController中的主要代码实现
为了方便起见本ViewController继承自UITableViewController具体实现代码如下:
//// MTableViewController.m// cell计算//// Created by code_xq on 16/3/12.// Copyright © 2016年 code_xq. All rights reserved.//#import "MTableViewController.h"#import "MTableViewCell.h"#import "DataModel.h"static NSString *ID = @"cell";@interface MTableViewController ()@property (nonatomic, strong) NSMutableArray *dataSource;@end@implementation MTableViewController- (void)viewDidLoad { [super viewDidLoad]; self.title = @"cell的高度计算"; // 去除tableView的默认下划线 self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; self.tableView.backgroundColor = [UIColor colorWithWhite:0.9 alpha:0.9]; // 注册cell [self.tableView registerClass:[MTableViewCell class] forCellReuseIdentifier:ID]; // 异步获取数据 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSString *path = [[NSBundle mainBundle] pathForResource:@"cellList.plist" ofType:nil]; NSArray *array = [NSArray arrayWithContentsOfFile:path]; for (NSDictionary *dict in array) { DataModel *dm = [DataModel initWith:dict]; [self.dataSource addObject:dm]; } // 造数据 [self.dataSource addObjectsFromArray:self.dataSource]; // 在主线程中刷新数据 dispatch_async(dispatch_get_main_queue(), ^{ [self.tableView reloadData]; }); });}#pragma mark - Table view data source- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.dataSource.count;}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { MTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID forIndexPath:indexPath]; cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.dataModel = self.dataSource[indexPath.row]; return cell;}- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { DataModel *dm = self.dataSource[indexPath.row]; return dm.cellHeight;}/** * 给出cell的估计高度,主要目的是优化cell高度的计算次数 */- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath { return 200;}/** * 初始化数据 */- (NSMutableArray *)dataSource { if (_dataSource == nil) { _dataSource = [NSMutableArray array]; } return _dataSource;}@end
这段代码是初始化tableView的常规做法,值得注意的是UITableView的
estimatedHeightForRowAtIndexPath 这个方法给出cell的预估值,如果没有实现这个方法,tableView内部会一次性将所有的cell的高度全部计算出来,有了这个方法会对tableView的性能有所提高,这个方法的返回值理论上可以是任意值。Model数据的代码实现
//// DataModel.h// cell计算//// Created by code_xq on 16/3/12.// Copyright © 2016年 code_xq. All rights reserved.//#import@interface DataModel : NSObject/** 文字内容 */@property (nonatomic, copy) NSString *text;/** 图标*/@property (nonatomic, copy) NSString *icon;/** 图片*/@property (nonatomic, copy) NSString *picture;/** 用户名*/@property (nonatomic, strong) NSString *name;/** cell的高度*/@property (nonatomic, assign) CGFloat cellHeight;+ (instancetype)initWith:(NSDictionary *)dict;@end/***********************类的实现*********************/#import "DataModel.h"@implementation DataModel+ (instancetype)initWith:(NSDictionary *)dict { DataModel *dm = [[self alloc] init]; [dm setValuesForKeysWithDictionary:dict]; return dm;}@end
数据是从plist中获取直接转换成DataModel对象的,这里多了一个cellHeight的属性用来存放cell的高度。
重头戏自定义cell的代码实现
//// MTableViewCell.h// cell计算//// Created by code_xq on 16/3/12.// Copyright © 2016年 code_xq. All rights reserved.//#import@class DataModel;@interface MTableViewCell : UITableViewCell/** 数据模型*/@property (nonatomic, strong) DataModel *dataModel;@end/***********************类的实现*********************/#import "MTableViewCell.h"#import "UIView+Expand.h"#import "DataModel.h"#define SCWIDTH [UIScreen mainScreen].bounds.size.width#define SCHEIGHT [UIScreen mainScreen].bounds.size.heightstatic CGFloat const margin = 10;@interface MTableViewCell()@property (nonatomic, weak) UIImageView *imageIcon;@property (nonatomic, weak) UILabel *labelName;@property (nonatomic, weak) UILabel *labelContent;@property (nonatomic, weak) UIImageView *picView;@end@implementation MTableViewCell- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { [self setUpView]; } return self;}- (void)setUpView { // 用户头像 UIImageView *imageIcon = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 50, 50)]; imageIcon.left = margin; imageIcon.top = margin; self.imageIcon = imageIcon; [self.contentView addSubview:imageIcon]; // 用户名 CGFloat nameW = SCWIDTH - imageIcon.width - 3 * margin; UILabel *labelName = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, nameW, 30)]; labelName.left = imageIcon.right + margin; labelName.top = margin; labelName.font = [UIFont systemFontOfSize:20]; self.labelName = labelName; [self.contentView addSubview:labelName]; // 文字内容 UILabel *labelContent = [[UILabel alloc] initWithFrame:CGRectMake(margin, 0, SCWIDTH - 20 , 30)]; labelContent.top = imageIcon.bottom + margin; // 设置显示多行文字 labelContent.lineBreakMode = NSLineBreakByCharWrapping; labelContent.numberOfLines = 0; labelContent.font = [UIFont systemFontOfSize:15]; self.labelContent = labelContent; [self.contentView addSubview:labelContent]; // 图片 UIImageView *picView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 120, 90)]; picView.left = margin; self.picView = picView; [self.contentView addSubview:picView];}- (void)setFrame:(CGRect)frame { frame = CGRectMake(frame.origin.x, frame.origin.y + 10, frame.size.width, frame.size.height - 10); [super setFrame:frame];}- (void)setDataModel:(DataModel *)dataModel { _dataModel = dataModel; // 设置用户头像 self.imageIcon.image = [UIImage imageNamed: dataModel.icon]; // 设置用户名 self.labelName.text = dataModel.name; // 计算文字内容的高度 CGFloat height = [dataModel.text boundingRectWithSize:CGSizeMake(SCWIDTH - 2 * margin, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : self.labelContent.font} context:nil].size.height; self.labelContent.height = height; self.labelContent.text = dataModel.text; // 设置图片内容 if (dataModel.picture) { self.picView.hidden = NO; self.picView.top = self.labelContent.bottom + margin; self.picView.image = [UIImage imageNamed:dataModel.picture]; dataModel.cellHeight = self.picView.bottom + 2 * margin; } else { self.picView.hidden = YES; dataModel.cellHeight = self.labelContent.bottom + 2 * margin; } }@end
为了布局方便自己给UIView写了个分类可以很容易获取view的left、top、right、bottom的值,好了到此复杂cell的高度计算就讲完了,如果有机会继续讲述AutoLayout自动布局下的cell高度的计算。