前言:在iOS程序開發中,
TableView
的實用是最常見的,在一些比較特殊的需求下,必須展示的是用戶評論信息,或發布的微博,這樣的情況下,固定高度的cell
顯然是不能實現我們的需求,這就需要我們根據需要展示的內容,動態的設置cell
的高度.下面是我做的一個Demo
, 我們一起來做一下如何去實現這樣的功能,希望能夠對你起到一定的幫助.下面是效果圖.
1 . 首先來我們分析一下這個需求,很顯然這是一個可以滑動的列表,很自然我們就會想到用tableView
去實現.在這個列表上面,每一個cell
存放一條用戶發送的數據,這些數據包括用戶的名字,用戶發送的正文內容,另外就是有一些是有配圖的,有一些是沒配圖的.另外就是單元格的高度會隨著內容的變化而變大或者變小.分析完這些,那我們開始擼代碼,既然我們沒有做過自適應高度的需求,那我們總做過高度固定的單元格吧,那就索性先給一個固定高度,然后再去調整. 接著我們去創建viewController.并且給tableView注冊自定義單元格.
self.tableView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStylePlain];
[self.tableView registerClass:[AdaptiveTableViewCell class] forCellReuseIdentifier:identifier];
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.view addSubview:self.tableView];
2 . 創建model
類,添加數據源,并且保存在數組中.這個數據源我是寫在了,plist
文件當中,并且使用cocoaPods
導入MJExtension
進行數據轉模型.
#pragma mark - 懶加載
- (NSArray *)dataSource {
if (!_dataSource) {
self.dataSource = [AdaptiveModel mj_objectArrayWithFilename:@"ModelList.plist"];
}
return _dataSource;
}
3 . 在自定義的cell
中添加重寫初始化方法,添加子控件.
// 重寫初始化方法
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self setupView];
}
return self;
}
// 添加子控件
- (void)setupView {
UILabel *nameLabel = [UILabel new];
[self.contentView addSubview:nameLabel];
nameLabel.textColor = [UIColor orangeColor];
nameLabel.font = [UIFont systemFontOfSize:17];
self.nameLabel = nameLabel;
UILabel *textLabel = [[UILabel alloc] init];
textLabel.numberOfLines = 0;
textLabel.font = [UIFont systemFontOfSize:14];
[self.contentView addSubview:textLabel];
self.text_Label = textLabel;
UIImageView *pictureView = [[UIImageView alloc] init];
[self.contentView addSubview:pictureView];
self.picthreView = pictureView;
}
4 . 注意在添加子控件的時候我是沒有給出控件的frame
的.因為單元格的高度要根據需要展示的內容來動態計算的,那我們就在model
類里面動態的計算出控件的frame
和cell
的高度,并且保存在model類中. 注意在model中要把#import <Foundation/Foundation.h>
框架更改成#import <UIKit/UIKit.h>
否則沒法添加CGRect
屬性.
#import <UIKit/UIKit.h>
// 模型
@interface AdaptiveModel : NSObject
@property (nonatomic, copy) NSString *name; // 昵稱
@property (nonatomic, copy) NSString *text; // 正文
@property (nonatomic, copy) NSString *picture; // 圖片
@property (nonatomic, assign) CGRect nameFrame; // 昵稱的frame
@property (nonatomic, assign) CGRect textFrame; // 正文的frame
@property (nonatomic, assign) CGRect pictureFrame; // 圖片的frame
@property (nonatomic, assign) CGFloat cellHeight; // 單元格高度
@end
5 .然后再model.m
中懶加載計算出各個控件的frame
和cell
的高度
#import "AdaptiveModel.h"
#define Space 10 // 間距
@implementation AdaptiveModel
// 懶加載
- (CGFloat)cellHeight {
if (_cellHeight == 0) {
CGFloat nameX = Space;
CGFloat namey = Space;
// 獲取文字寬度
// CGSize nameSzie = [self getLabalSizeWithLabel:self.nameLabel];
NSDictionary *attribute = @{NSFontAttributeName : [UIFont systemFontOfSize:17]};
CGSize nameSize = [self.name sizeWithAttributes:attribute];
self.nameFrame = CGRectMake(nameX, namey, nameSize.width, nameSize.height);
// 正文
CGFloat textW = [UIScreen mainScreen].bounds.size.width - Space * 2;
NSDictionary *attribute1 = @{NSFontAttributeName: [UIFont systemFontOfSize:14]};
CGSize textsize = [self.text boundingRectWithSize:CGSizeMake(textW, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:attribute1 context:nil].size;
// CGFloat textH = [self getLabelSizeWithLabel:self.text_Label width:textW];
self.textFrame = CGRectMake(Space, CGRectGetMaxY(self.nameFrame) + Space, textW, textsize.height);
// 圖片
if (self.picture) {
self.pictureFrame = CGRectMake(Space, CGRectGetMaxY(self.textFrame) + Space, 100, 100);
_cellHeight = CGRectGetMaxY(self.pictureFrame) + Space;
} else {
_cellHeight = CGRectGetMaxY(self.textFrame) + Space;
}
}
return _cellHeight;
}
@end
注意事項:
注意在此時用到了2個方法,第一個是獲取文字尺寸,這個方法僅限于label
沒有換行,需要獲取文字寬度時使用.需要注意的地方就是設置的font
和你label
控件設置的font
必須是一致的.
// 獲取文字寬度
NSDictionary *attribute = @{NSFontAttributeName : [UIFont systemFontOfSize:17]};
CGSize nameSize = [self.name sizeWithAttributes:attribute];
第二個方法也是獲取文字尺寸,和第一個方法不同的是這個是可以換行的,需要注意的是不僅要設置
font
和你設置的label
的font
必須是一致的,還要給它設置一個最大的寬度,告訴它最大寬度時多少,才會自動換行.
// 正文
CGFloat textW = [UIScreen mainScreen].bounds.size.width - Space * 2;
NSDictionary *attribute1 = @{NSFontAttributeName: [UIFont systemFontOfSize:14]};
CGSize textsize = [self.text boundingRectWithSize:CGSizeMake(textW, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:attribute1 context:nil].size;
6 .接下來我們計算好了cell的高度,就在tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
這個方法中設置cell
的高度就可以了.
// 設置單元格高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
AdaptiveModel *model = self.dataSource[indexPath.row];
return model.cellHeight;
}
7 . 設置單元格,給單元格上的控件賦值
// 設置單元格
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
AdaptiveTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
// 傳遞數組模型
cell.model = self.dataSource[indexPath.row];
return cell;
}
8 .在自定義的cell
里面重寫屬性的setter方法,給子控件賦值,并且設置控件的frame
// 重寫屬性的setter方法
- (void)setModel:(AdaptiveModel *)model {
if (_model != model) {
_model = model;
}
self.nameLabel.text = model.name;
self.text_Label.text = model.text;
if (model.picture) { // 有圖片
self.picthreView.hidden = NO;
self.picthreView.image = [UIImage imageNamed:model.picture];
} else { // 沒有圖片
self.picthreView.hidden = YES;
}
// 設置控件的frame
self.nameLabel.frame = self.model.nameFrame;
self.text_Label.frame = self.model.textFrame;
self.picthreView.frame = self.model.pictureFrame;
}
總結:以上就是自適應
TableViewCell
的全過程,我們可以得出以下的結論,要想去實現tableView
自適應高度,首先我們需要計算出model
中各個控件的frame
和所需要的cell
的高度.然后再設置單元格高度的方法中,設置單元格所需要的高度.最后再把各個控件的frame
傳遞到cell
中來設置.當然還有其他的實現方法, 我這里只是給出了一個思路,具體怎么實現,還需要你自己去動腦子思考,希望能夠對你起到一定的幫助作用.
另附gitHub下載地址