1.xib方式創建
每個cell的顯示的內容都是固定的,也就是cell的高度都是相同的
加載數據
有plist文件數據結構如下
創建數據模型
Product.h
@interface Product : NSObject
@property (nonatomic , copy) NSString *name;
@property (nonatomic , copy) NSString *location;
@property (nonatomic , copy) NSString *count;
@property (nonatomic , copy) NSString *price;
@property (nonatomic , copy) NSString *icon;
- (instancetype)initWithDict:(NSDictionary *)dict;
+ (instancetype)goodsWithDict:(NSDictionary *)dict;
@end
Product.m
@implementation Product
- (instancetype)initWithDict:(NSDictionary *)dict{
if (self = [super init]) {
self.name = dict[@"name"];
self.location = dict[@"location"];
self.count = dict[@"minproduct"];
self.price = dict[@"price"];
self.icon = dict[@"icon"];
// [self setValuesForKeysWithDictionary:dict];
}
return self;
}
+ (instancetype)goodsWithDict:(NSDictionary *)dict{
return [[self alloc]initWithDict:dict];
}
@end
懶加載數據
PageFirstTableViewController.m
//用來存儲所有團購商品的數據
@property (nonatomic , strong) NSMutableArray *goods;
#pragma mark -lazyload
- (NSMutableArray *)goods{
if (_goods ==nil) {
NSString *path = [[NSBundle mainBundle]pathForResource:@"dataSource.plist" ofType:nil];
NSArray *arrayDict = [NSArray arrayWithContentsOfFile:path];
//字典轉模型
NSMutableArray *arrayModels = [NSMutableArray array];
for (NSDictionary *dict in arrayDict) {
Product *model = [Product goodsWithDict:dict];
[arrayModels addObject:model];
}
_goods = arrayModels;
}
return _goods;
}
實現數據源協議
通過xib方式實現自定義cell
創建以一個.xib文件。在xib中拖一個UITableViewCell,設置高寬。向UITableViewCell中拖子控件。
創建一個繼承自UITableViewCell的類ProductCell與xib文件的cell相關聯。通過拖線的方式將cell的子控件拖線到ProductCell的屬性上。
ProductCell.m
@property (weak, nonatomic) IBOutlet UILabel *name;
@property (weak, nonatomic) IBOutlet UILabel *price;
@property (weak, nonatomic) IBOutlet UIImageView *icon;
....略
實現數據源協議
PageFirstTableViewController.m
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.goods.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//1.獲取模型數據
Product *model = self.goods[indexPath.row];
//2.創建單元格
//通過xib創建單元格
//由于此方法調用十分頻繁,cell的標示聲明成靜態變量有利于性能優化
static NSString *ID = @"goods_cell"; //要在xib中設置這個id
ProductCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (cell == nil) {
//加載xib文件,loadNibName:方法返回的是一個數組,因為xib中可能有不止一個控件
cell = [[[NSBundle mainBundle]loadNibNamed:@"ProductCell" owner:nil options:nil] firstObject];//不能加xib后綴
}
//3.把模型數據設置給單元格
cell.name.text = model.name;
cell.price.text = [NSString stringWithFormat:@"¥%@", model.price];
cell.icon.image = [UIImage imageNamed: model.icon];
...賦值,略
//4.返回單元格
return cell;
}
在控制器中直接為cell重的每個子控件賦值數據造成的問題:
1.控制器強依賴于cell,一旦cell內部子控件發生了變化,那么控制器中的代碼也得改(緊耦合)。控制器完全依賴于單元格里面的屬性。
2.cell的封裝不夠完整,凡是用到cell的地方,每次都要編寫為cell的子控件依次賦值的語句,比如:cell.xxx = model.xxx。如果有10個控制器,每個控制器里都需要用到單元格進行賦值,如果一個單元格里有10個子控件,那么上面這樣的代碼就要寫10次。
對自定義cell進行封裝,把模型數據設置給單元格,形如:cell.goods = model;由cell對象內部自己來解析模型數據,并把數據設置到對應的子控件中。在cell中創建一個模型類型的屬性,重寫該屬性的set方法,在set方法中將數據賦值給控件。
ProductCell.h
#import "Product.h"
@interface ProductCell : UITableViewCell
@property (nonatomic , strong) Product *goods;
//封裝一個創建自定義cell的方法
+ (instancetype)productCellWithTableView:(UITableView *)tableView;
@end
ProductCell.m
//重寫set方法
- (void)setGoods:(Product *)goods{
_goods =goods;
self.name.text = goods.name;
self.price.text = [NSString stringWithFormat:@"¥%@",goods.price];
self.icon.image = [UIImage imageNamed:goods.icon];
self.location.text = goods.location;
self.count.text = [NSString stringWithFormat:@"最低批發量:%@",goods.count];
}
+ (instancetype)productCellWithTableView:(UITableView *)tableView{
static NSString *ID = @"goods_cell";
ProductCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (cell == nil) {
cell = [[[NSBundle mainBundle]loadNibNamed:@"ProductCell" owner:nil options:nil] firstObject];//不能加xib后綴
}
return cell;
}
修改后的數據源方法
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
Product *model = self.goods[indexPath.row];
ProductCell *cell = [ProductCell productCellWithTableView:tableView];
cell.goods = model;
return cell;
}
注意:要設置tableView.rowHeight = xib中的cell的高度。不然會報警告
2.純代碼方式創建(frameLayout,自適應高度)
每個cell顯示的內容不固定,cell的高度需要根據內容的多少自適應高度(例如微博,朋友圈):
iOS開發UI篇—使用純代碼自定義UItableviewcell實現一個簡單的微博界面布局
使用純代碼自定義一個tableview的步驟
1.新建一個繼承自UITableViewCell的類
2.重寫initWithStyle:reuseIdentifier:方法
添加所有需要顯示的子控件(不需要設置子控件的數據和frame, 子控件要添加到contentView中)
進行子控件一次性的屬性設置(有些屬性只需要設置一次, 比如字體\固定的圖片)
3.提供2個模型
數據模型: 存放文字數據\圖片數據
frame模型: 存放數據模型\所有子控件的frame\cell的高度
4.cell擁有一個frame模型(不要直接擁有數據模型)
5.重寫frame模型屬性的setter方法: 在這個方法中設置子控件的顯示數據和frame
6.frame模型數據的初始化已經采取懶加載的方式(每一個cell對應的frame模型數據只加載一次)
原文例子里自定義cell自適應高度是通過加減乘除運算來計算出來的,沒有使用autolayout
結合鏈接原文里面的例子,講一下自己的個人理解。
步驟2:NJWeiboCell.m文件,在重寫的
initWithStyle:reuseIdentifier:
方法里創建并添加子控件到contentView上,注意創建的子控件屬性要聲明為weak。另外,像微博vip皇冠圖標這種固定的內容的控件,進行一次性數據設置即可。步驟3、4:除了數據模型(NJWeibo.m)以外還需要frame模型,自定義cell持有frame模型,frame模型持有數據模型。
為什么還需要frame模型?如果沒有frame模型,那么自定義cell中直接持有數據模型,即- (void)setWeiboFrame:(NJWeiboFrame *)weiboFrame
替換為- (void)setWeibo:(NJWeibo *)weibo
,然后在- (void)settingFrame
方法中詳細設置控件frame,得出cell的高度。每個cell的高度是隨子控件內容而變化的。
但是在tableView中,- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
設置行高的代理方法要比- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
方法先調用。如果沒有提供frame模型,那么要直到執行數據源方法,把模型數據設置給單元格(形如:cell.weibo = model;
)時,才能獲取得到cell的行高。
如果獨立出frame模型,就可以在frame模型中詳細設置控件frame,得出cell高度,然后在設置行高的代理方法中取出對應的frame模型中的行高。獲取文本lable的寬和高:
- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(NSDictionary *)attributes context:(NSStringDrawingContext *)context ;
參數1是計算大小的指定范圍;如果將來計算的文字的范圍超出了指定的范圍,返回的就是指定的范圍;如果沒有超出那么返回的就是真實的范圍;不限制范圍的話設置CGSizeMake(MAXFLOAT, MAXFLOAT)就可以了。要注意的是:如果是獲取多行文本的話,在此之前需要設置文本控件的numberOfLines屬性為0。
另外,如果是獲取單行文本的size :可以用sizeWithAttributes:方法
更新:使用xib創建自適應高度的tableViewCell
UITableViewCell高度自適應探索這篇文章寫得挺細致的,沒有其他要補充,大致上和用代碼創建自適應高度cell的實現原理上是一樣的。比起使用frameLayout創建cell要簡單一點,不需要另外設置frame模型來存放所有子控件的frame、cell的高度。
現在有個第三方框架可以很方便地創建高度自適應的tableView cell:
優化UITableViewCell高度計算的那些事
UITableView+FDTemplateLayoutCell 源碼閱讀