自定义Cell的两种方法
1>通过xib来自定义cell (如果位置和宽高固定)
2>通过代码来自定义cell
第一种方法:通过xib来自定义cell(拖控件方便,但是2个重用标识要改为一样)
将控制器头文件中继承的UIViewController改为继承UITableViewController,
则系统自动将UITableView的数据源和代理设置为控制器,并且已经遵守了协议,大概实现了数据源方法和代理方法,并且控制器View就是TableView,不存在View里面又有一个TableView的情况。(self.view == self.tableView)
//总结:如果以后只是想展示表格,就用这个方法即可。
将之前storyboard里面的View删除,然后拖一个UITableView
1>创建一个xib文件,拖好控件
2>在控制器实现文件的cellForRowAtIndexPath:方法里加载xib文件
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 0.定义循环标记
static NSString *CellIdentifier = @”news“;
PS:同时在xib文件中给cell绑定一个供循环利用的identifier,也设置为news
// 1.从缓存池中取出cell
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
// 2.缓存池中没有cell
if (cell ==nil){
NSArray *objects = [[NSBundle mainBundle]
loadNibNamed:@"NewsCell" owner:nil options:nil];
//bundle相当于一个压缩包,传nil默认为mainBundle
cell = objects[0];
}
return cell;
}
3>设置cell的高度
方法1:通过代理方法heightForRowAtIndexPath:返回cell的高度(如果高度不一定一样:就用这个,可以根据行号返回不同的高度)
方法2:在viewDidLoad中 self.tableView.rowHeight = X(只适合高度一样的场合)
cell的封装
1>将新闻图片放到支持文件中,创建一个plist文件(Root为Array)
2>新建一个模型类News来加载plist文件,在News.h中声明4个属性,并声明构造方法和类方法
3>在News.m中实现构造方法和类方法
-(id)initWithDict:(NSDictionary *)dict
{
if (self = [super init]) {
//解析字典属性
self.title = dict[@"title"];
self.icon = dict[@"icon"];
self.author = dict[@"author"];
self.comments = [dict[@"comments"] intValue];
}
return self;
}
+ (id)newsWithDict:(NSDictionary *)dict
{
return [[self alloc] initWithDict:dict];
}
4>在控制器实现文件中导入News.h
并在viewDidLoad中加载plist数据
NSArray *array = [NSArray arrayWithContentsOfFile:[NSBundle mainBundle] pathForResource:"news.plist" ofType:nil];
PS:在类扩展中声明一个数组成员变量 NSMutableArray *newses;
// 字典转模型
_newses = [NSMutableArray array];
//遍历array里面的所有新闻字典并将其转为模型,加到上面的数组中
for (NSDictionary *dict in array){
[_newses addObject:[News newsWithDict:dict]];
}
}
5>修改数据源方法
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _news.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)
indexPath
{
........
//3.取出新闻模型
News *news = _newses[indexPath.row];
//如果通过绑定tag来取出数据那么控制器知道太多,不利于扩展,所以应该封装cell,以增加重用性。
}
正式开始cell的封装
6>新建一个类NewsCell来封装cell,继承自UITableViewCell,并将xib文件的Class设置为NewsCell。
然后在NewsCell.h中声明4个outlet的属性,连接对应子控件,然后提供一个类方法
+(id)newsCell并实现它(用来创建cell)
+(id)newsCell
{
return [[NSBundle mainBundle loadNibNamed:@"NewsCell" owner:nil options:nil][0];
}
7>在控制器的实现文件中导入NewsCell.h
再次修改数据源方法(现在代码非常精简,并且扩展性好)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)
indexPath
{
......
// 1.从缓存池中取出cell(这里取出的应该是NewsCell)
NewsCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
// 2.缓存池中没有cell
if (cell ==nil){
cell = [NewsCell newsCell]; //这里创建的也应该是NewsCell
}
//3.传递模型数据(在完成第8步和 第9步后)
cell.news = _newses[indexPath.row];
//点语法本质就是set方法,所以会直接到重写的set方法中
return cell;
}
8>在NewsCell的头文件中
@class News;
@property (nonatomic,strong)News *news //模型数据
9>在NewsCell的实现文件中
import "News.h"
//重写set方法
-(void)setNews:(News *)news
{
_news = news;
//1.标题
_titleLabel.text = news.title;
//2.作者
_authorLabel.text = news.author;
//3.评论数
_commentsLabel.text = [NSString stringWithFormat:@"评论:%d" ,news.conments];
//4.图片
_iconView.image = [UIImage imageNamed:news.icon];
}
cell代码的重用
现在控制器还知道重用的标识,这样不好。所以在NewsCell的头文件中写一个类方法,返回重用的标识,然后在控制器的m文件中再调用这个类方法即可。
原则:做任何改变,控制器都不应该改代码。cell不依赖于控制器。控制器应该非常闲,只负责传递数据。控制器与这个cell几乎没有耦合性。所以在做其他项目时,这个cell可以直接拿来用,让新的控制器实现数据源方法即可,非常简单。(反之如果控制器管的过多,那么cell重用起来就没那么容易了。)