前言
前面幾個章節詳細介紹了Aspect Ratio、Content Hugging Priority(抗拉伸優先順序)和Content Compression Resistance Priority(抗壓縮優先順序),
本文將綜合運用這些特性,在不計算UITableViewCell高度、不使用第三方自動計算高度框架的前提下,來實現UITableViewCell自動高度.
一. UITableViewCell自動高度:
iOS8 WWDC 中推出了 self-sizing cell 的概念,旨在讓 cell 自己負責自己的高度計算,
由於之前APP 需要相容iOS7,所以很多開發者由於考慮到相容iOS7,還是使用手動計算高度,或第三方自動計算高度框架,來計算動態UITableViewCell高度,
但隨著Xcode9普及,開發工具限制了最低只能相容到iOS8,所以我們可以好好運用這一特性了,不必在使用傳統方式來處理動態UITableViewCell高度了.
二.自動高度Demo效果(此效果模仿悟空問答某一介面)
三.實現部分
1.UITableView只需要做如下設定
- 如下:
//cell預估高度,設一個接近cell高度的值
self.tableView.estimatedRowHeight = 100;//也可以省略不設定,
//設定rowHeight為UITableViewAutomaticDimension,
self.tableView.rowHeight = UITableViewAutomaticDimension;//可以省略不設定
複製程式碼
- 不實現UITableView返回cell高度代理方法
/**
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
//不實現
}
*/
複製程式碼
2. AutoLayout部分
- cell AutoLayout部分新增好各控制元件約束,並設定好動態高度控制元件的Content Hugging Priority和Content Compression Resistance Priority優先順序即可
四.實際運用
下面我們一起來看下,在不計算高度的前提下,怎麼實現上面悟空問答介面效果
1.程式碼部分
程式碼部分很簡單,就一個簡單的UITableView,自定義一個cell,如下:
#import "ViewController.h"
#import "DemoModel.h"
#import "YYModel.h"
#import "DemoCell.h"
static NSString *const id_DemoCell = @"DemoCell";
@interface ViewController ()<UITableViewDataSource,UITableViewDelegate>
@property (nonatomic, strong) NSArray *dataArray;
@property (nonatomic, strong) UITableView *tableView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.tableView];
[self.tableView registerNib:[UINib nibWithNibName:id_DemoCell bundle:nil] forCellReuseIdentifier:id_DemoCell];
}
#pragma mark - tableView
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.dataArray.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
DemoCell *cell = [tableView dequeueReusableCellWithIdentifier:id_DemoCell];
if (!cell) {
cell = [[DemoCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:id_DemoCell];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
DemoModel *model = self.dataArray[indexPath.row];
cell.model = model;
return cell;
}
#pragma mark - lazy
-(UITableView *)tableView{
if(!_tableView){
_tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height) style:UITableViewStylePlain];
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.estimatedRowHeight = 250;//預估高度
_tableView.rowHeight = UITableViewAutomaticDimension;
}
return _tableView;
}
/** 從檔案載入資料 */
-(NSArray *)dataArray{
if(!_dataArray){
NSString *path = [[NSBundle mainBundle] pathForResource:@"demo" ofType:@"json"];
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:path] options:0 error:nil];
_dataArray = [NSArray yy_modelArrayWithClass:[DemoModel class] json:json[@"data"]];
}
return _dataArray;
}
@end
複製程式碼
2.UITableViewCell AutoLayout部分
-
新建一個cell命名DemoCell,新增子控制元件如圖
-
並脫線生成如下變數
@property (weak, nonatomic) IBOutlet UIImageView *iconView;//影像
@property (weak, nonatomic) IBOutlet UILabel *nameLab;//名字
@property (weak, nonatomic) IBOutlet UILabel *timeLab;//時間
@property (weak, nonatomic) IBOutlet UILabel *titleLab;//標題
@property (weak, nonatomic) IBOutlet UILabel *contentLab;//內容
@property (weak, nonatomic) IBOutlet UILabel *commentLab;//評論數
@property (weak, nonatomic) IBOutlet UILabel *praiseLab;//點贊數
複製程式碼
- 並新增如下約束
影像-iconView約束:上15,左15,高30,寬高比1:1
名字-nameLab約束:上下均對其iconView,左5, 並設定橫向抗壓縮優先順序為749即Content Compression Resistance Priority - Horizontal:749
時間-timeLab約束:上下均對齊iconView,左5, 並設定橫向抗拉伸優先順序為250即Content Hugging Priority - Horizontal:250
關注按鈕約束:上下均對齊iconView,右15,寬度50,左5
標題-timeLab約束:左15,上15,右15,
內容-contentLab約束:左15,上15,右15,並設定並設定縱向抗拉伸優先順序為250即Content Hugging Priority - Vertical:250
三張圖約束:上15,左15,右15,中間間隙5,高度65,並設定三張圖等寬,
評論數-commentLab約束:上15,左15,下15,
點贊數-praiseLab約束:上下對齊commentLab,左5,右邊15,並設定橫向抗拉伸優先順序為250即Content Hugging Priority - Horizontal:250
複製程式碼
3.UITableViewCell控制元件賦值部分
-(void)setModel:(DemoModel *)model{
_model = model;
[_iconView sd_setImageWithURL:[NSURL URLWithString:model.icon]];
_nameLab.text = model.name;
_timeLab.text = model.update_time;
_contentLab.text = model.brief;
_titleLab.text = model.title;
_commentLab.text = [NSString stringWithFormat:@"%ld評論",model.comment];
_praiseLab.text = [NSString stringWithFormat:@"%ld贊",model.praise];
for (int i = 0; i<3; i++) {
UIImageView *imgView = [self viewWithTag:10+i];
imgView.image = nil;
}
for (int i = 0; i<model.images.count; i++) {
UIImageView *imgView = [self viewWithTag:10+i];
[imgView sd_setImageWithURL:[NSURL URLWithString:model.images[i]]];
}
}
複製程式碼
- 到此,我們已經完成上圖demo效果,是不是很簡單,沒有寫任何高度計算的程式碼.
五.關於組頭、組尾
- UITableView 的組頭和組尾,也可以實現自動高度,設定方法如下:
_tableView.sectionHeaderHeight = UITableViewAutomaticDimension;
_tableView.estimatedSectionHeaderHeight = 100;//組頭預估高度
_tableView.sectionFooterHeight = UITableViewAutomaticDimension;
_tableView.estimatedSectionFooterHeight = 100;//組尾預估高度
複製程式碼
- 並且不實現下面兩個組頭,組尾高度代理方法
/**
-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
//不實現
}
*/
/**
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
//不實現
}
*/
複製程式碼
六.關於動態高度,和固定高度混用
- 此場景通常出現在,一個TableView有多種樣式的cell情況下,
- 例如:組0的cell是固定高度,其他組的cell是動態高度,要怎麼設定呢?
- 方法如下:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
if(indexPath.section==0){
return 100;//固定高度
}else{
return UITableViewAutomaticDimension;//動態高度
}
}
複製程式碼
七.小結
- 1.UITableViewCell動態高度,程式碼設定部分很簡單不難,主要是AutoLayout部分,要想使用起來,得心應手,開發者除了要掌握普通AutoLayout約束外,還必須熟練掌握Content Hugging Priority(抗拉伸優先順序)和Content Compression Resistance Priority(抗壓縮優先順序)的用法.
- 2.熟練使用UITableView cell、組頭、組尾自動高度,能給我開發節省大量的時間.
- 3.如對Content Hugging Priority(抗拉伸優先順序)和Content Compression Resistance Priority(抗壓縮優先順序)的用法不熟練的同學,可以看我前面文章:AutoLayout進階(二)、 AutoLayout進階(三)、AutoLayout進階(四),有詳細介紹兩個優先順序的用法.
程式碼地址:github.com/CoderZhuXH/…