在個人平常開發中常常會遇到cell內容比較複雜的狀況,複雜的cell勢必會有cell高度不相同的狀況,這種需求每每是比較蛋疼的。可是不要緊只要掌握了其中的原理剩下的就只是體力活了。本文采用傳統方式純代碼佈局來計算cell的高度值,若是精力容許下篇介紹AutoLayout自動佈局下的cell高度的計算。app
爲了方便起見本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的性能有所提升,這個方法的返回值理論上能夠是任意值。async
// // DataModel.h // cell計算 // // Created by code_xq on 16/3/12. // Copyright © 2016年 code_xq. All rights reserved. // #import <UIKit/UIKit.h> @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的高度。佈局
// // MTableViewCell.h // cell計算 // // Created by code_xq on 16/3/12. // Copyright © 2016年 code_xq. All rights reserved. // #import <UIKit/UIKit.h> @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.height static 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高度的計算。性能