TableView使用
1.tableView如何显示数据
- 设置dataSource数据源方法
- 数据源要遵守UITableViewDataSource协议
- 数据源要实现协议中的某些方法
1.告诉tableView第Section组有多少行
-(NSInterger)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
2.告诉tableView第indexPath行显示怎样的cell
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexpath
3.告诉TableView第section组头部标题
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
4.告诉tableView第section组的尾部标题
-(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
UITableView的常见设置
//1.分割线颜色
self.tableView.separetorColor = [UIColor redColor];
//2.隐藏分割线
self.tableView.separatorStyle = [UITableViewCellSeparatorStyleNone];
//3.取消选中样式
cell.selectionStyle = UITableViewCellSelectionStyleNone;
//4.设置选中的背景色
UIView *selectedBackgroundView = [[UIView alloc] init];
selectedBackgroundView.backgroundColor = [UIColor redColor];
cell.selectedBackgroundView = selectedBackgroundView;
//5.设置默认的背景色
cell.backgroundColor = [UIColor blueColor];
//6.设置默认的背景色
UIView *backgroundView = [[UIView alloc] init];
backgroundView.backgroundColor = [UIcolor greenColor];
cell.backgroundView = backgroundView;
//7.设置指示器
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.accessoryView = [[UISwitch alloc] init];
cell的循环利用
1.什么时候调用cell呢?
每当有一个cell进入视野范围内就会调用
1.循环利用方式1
/**
* 什么时候调用:每当有一个cell进入视野范围内就会调用
*/
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 0.重用标识
// 被static修饰的局部变量:只会初始化一次,在整个程序运行过程中,只有一份内存
static NSString *ID = @"cell";
// 1.先根据cell的标识去缓存池中查找可循环利用的cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
// 2.如果cell为nil(缓存池找不到对应的cell)
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
}
// 3.覆盖数据
cell.textLabel.text = [NSString stringWithFormat:@"testdata - %zd", indexPath.row];
return cell;
}
2.循环利用方式2
(1)定义一个全局变量
//定义重用标识
NSString *ID = @"cell";
(2)注册某个标识对应的cell类型
//在viewDidLoad中注册cell
- (void)viewDidLoad {
[super viewDidLoad];
// 注册某个标识对应的cell类型
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:ID];
}
(3)在数据源方法中返回cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//1.去缓存池中查找cell
UITabelViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
//2.覆盖数据
cell.textLabel.text = [NSString stringWithFormat:@"testdata - %zd",indexPath.row];
return cell;
自定义cell
xib自定义等高cell
- 1.创建一个继承自UITableViewCell的子类,比如DealCell
- 2.创建一个xib文件(文件名建议和cell的类名一样,比如DealCell.xib)
- 拖拽一个UITableViewCell出来
- 修改cell的class为DealCell
- 设置cell的重用标识
- 往cell中添加需要用到的子控件 - 3.在控制器中
- 利用registerNib....方法中注册xib文件
- 利用重用标识找到cell(如果没有注册xib文件,就需要手动去加载xib文件)
- 给cell传递模型数据
- 4.在DealCell中
- 将xib中的子控件连线到类拓展中 即DealCell.m文件中
- 需要提供一个模型属性,重写模型的set方法,在这个方法中设置模型数据到子控件上
- 也可以将创建获得cell的代码封装起来
重写set方法 设置数据
- (void)setDeal:(XMGDeal *)deal
{
_deal = deal;
// 设置数据
self.iconView.image = [UIImage imageNamed:deal.icon];
self.titleLabel.text = deal.title;
self.priceLabel.text = [NSString stringWithFormat:@"¥%@", deal.price];
self.buyCountLabel.text = [NSString stringWithFormat:@"%@人已购买", deal.buyCount];
}
模型比如如下代码:
Status.h
@interface XMGStatus : NSObject
@property (strong, nonatomic) NSString *name;
@property (strong, nonatomic) NSString *text;
@property (strong, nonatomic) NSString *icon;
@property (strong, nonatomic) NSString *picture;
@property (assign, nonatomic, getter=isVip) BOOL vip;
+ (instancetype)statusWithDict:(NSDictionary *)dict;
@end
Status.m
@implementation XMGStatus
+ (instancetype)statusWithDict:(NSDictionary *)dict
{
XMGStatus *status = [[self alloc] init];
[status setValuesForKeysWithDictionary:dict];
return status;
}
@end
代码自定义cell(frame)
- 1.创建一个继承自UITableViewCell的子类,比如DealCell
- 在initWithStyle:reuseIdentifier:方法中
- 添加子控件
- 设置子控件的初始化属性(比如文字颜色、字体)
- 2.在控制器中
- 利用registerClass...方法注册DealCell类
- 利用重用标识找到cell(如果没有注册类,就需要手动创建cell)
- 给cell传递模型数据
- 也可以将创建获得的cell的代码封装起来
在initWithStyle:reuseIdentifier方法中添加子控件
// 1.在initWithStyle:reuseIdentifier:方法中添加子控件
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
UIImageView *iconView = [[UIImageView alloc] init];
[self.contentView addSubview:iconView];
self.iconView = iconView;
UILabel *titleLabel = [[UILabel alloc] init];
[self.contentView addSubview:titleLabel];
self.titleLabel = titleLabel;
UILabel *priceLabel = [[UILabel alloc] init];
priceLabel.textColor = [UIColor orangeColor];
[self.contentView addSubview:priceLabel];
self.priceLabel = priceLabel;
UILabel *buyCountLabel = [[UILabel alloc] init];
buyCountLabel.textAlignment = NSTextAlignmentRight;
buyCountLabel.font = [UIFont systemFontOfSize:14];
buyCountLabel.textColor = [UIColor lightGrayColor];
[self.contentView addSubview:buyCountLabel];
self.buyCountLabel = buyCountLabel;
}
return self;
}
fram代码如下:
// 2.在layoutSubviews方法中设置子控件的frame
- (void)layoutSubviews
{
[super layoutSubviews];
CGFloat contentH = self.contentView.frame.size.height;
CGFloat contentW = self.contentView.frame.size.width;
CGFloat margin = 10;
CGFloat iconX = margin;
CGFloat iconY = margin;
CGFloat iconW = 100;
CGFloat iconH = contentH - 2 * iconY;
self.iconView.frame = CGRectMake(iconX, iconY, iconW, iconH);
// titleLabel
CGFloat titleX = CGRectGetMaxX(self.iconView.frame) + margin;
CGFloat titleY = iconY;
CGFloat titleW = contentW - titleX - margin;
CGFloat titleH = 21;
self.titleLabel.frame = CGRectMake(titleX, titleY, titleW, titleH);
// CGRectMake(titleX, titleY�, titleW, titleH);
// priceLabel
CGFloat priceX = titleX;
CGFloat priceH = 21;
CGFloat priceY = contentH - margin - priceH;
CGFloat priceW = 70;
self.priceLabel.frame = CGRectMake(priceX, priceY, priceW, priceH);
// buyCountLabel
CGFloat buyCountH = priceH;
CGFloat buyCountY = priceY;
CGFloat buyCountX = CGRectGetMaxX(self.priceLabel.frame) + margin;
CGFloat buyCountW = contentW - buyCountX - margin;
self.buyCountLabel.frame = CGRectMake(buyCountX, buyCountY, buyCountW, buyCountH);
}
代码自定义cell(autolayout)
- 1.创建一个继承自UITableViewCell的子类,比如XMGDealCell
- 在initWithStyle:reuseIdentifier:方法中
- 添加子控件
- 添加子控件的约束(建议使用
Masonry
) - 设置子控件的初始化属性(比如文字颜色、字体)
- 需要提供一个模型属性,重写模型的set方法,在这个方法中设置模型数据到子控件
- 2.在控制器中
- 利用registerClass...方法注册XMGDealCell类
- 利用重用标识找到cell(如果没有注册类,就需要手动创建cell)
- 给cell传递模型数据
- 也可以将创建获得cell的代码封装起来(比如cellWithTableView:方法)
autolayout代码如下
- (void)viewDidLoad {
[super viewDidLoad];
[self performSelector:@selector(test1) withObject:self afterDelay:5];//5秒后执行test1
//蓝色控件
UIView *blueView = [[UIView alloc] init];
blueView.backgroundColor = [UIColor blueColor];
[self.view addSubview:blueView];
//红色控件
UIView *redView = [[UIView alloc] init];
redView.backgroundColor = [UIColor redColor];
[self.view addSubview:redView];
//添加约束
CGFloat margin = 20;
CGFloat height = 50;
//蓝色控件的约束
[blueView makeConstraints:^(MASConstraintMaker *make){
make.left.equalTo(self.view.left).offset(margin);//左边与父控件间距20
make.right.equalTo(redView.left).offset(-margin);//右边与红色控件间距20
make.bottom.equalTo(self.view.bottom).offset(-margin);//底部与父控件的底部间距20
make.height.equalTo(height);//
make.top.equalTo(redView.top);
make.bottom.equalTo(redView.bottom);
make.width.equalTo(redView.width);
}];
//红色控件的约束
[redView makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(self.view.right).offset(-margin);
}];
}
!!非等高的cell
xib自定义(重点)
- 1.创建一个继承自UITableViewCell的子类,比如XMGDealCell
- 2.创建一个xib文件(文件名建议跟cell的类名一样),比如StatusCell.xib
- 拖拽一个UITableViewCell出来
- 修改cell的class为StatusCell
- 设置cell的重用标识
- 往cell中添加需要用到的子控件
- 3.在控制器中
- 利用registerNib...方法注册xib文件
- 利用重用标识找到cell(如果没有注册xib文件,就需要手动去加载xib文件)
- 给cell传递模型数据
- 4.在XMGDealCell中
- 将xib中的子控件连线到类扩展中
- 需要提供一个模型属性,重写模型的set方法,在这个方法中设置模型数据到子控件上
- 也可以将创建获得cell的代码封装起来(比如cellWithTableView:方法) - 在模型中增加一个cellHeight属性,用来存放对应cell的高度
- 在cell的模型属性set方法中调用[self layoutIfNeed]方法强制布局,然后计算出模型的cellheight属性值
- 在控制器中实现tableView:estimatedHeightForRowAtIndexPath:方法,返回一个估计高度,比如200
- 在控制器中实现tableView:heightForRowAtIndexPath:方法,返回cell的真实高度(模型中的cellHeight属性)
示例模型代码如下
status.h
//微博模型
@interface Status_M : NSObject
@property (nonatomic,strong) NSSet *name;
@property (nonatomic,strong) NSSet *text;
@property (nonatomic,strong) NSString *icon;
@property (nonatomic,strong) NSString *picture;
@property (assign, nonatomic, getter=isVip) BOOL vip;
//cell的高度
@property (assign, nonatomic) CGFloat cellHeight;
+(instancetype)statusWithDict:(NSDictionary *)dict
status.m
@implementation Status_M
+(instancetype)statusWithDict:(NSDictionary *)dict
{
Status_M *status = [[self alloc] init];
[status setValuesForKeysWithDictionary:dict];
return status;
}
@end
自定义cell封装代码如下
StatusCell.h
#import <UIKit/UIKit.h>
@class Status_M;
@interface StatusCell : UITableViewCell
+(instancetype)cellWithTableView:(UITableView *)tableView;
//微博模型数据
@property (nonatomic, strong) Status_M *status;
@end
StatusCell.m
#import "StatusCell.h"
#import "Status_M.h"
@interface StatusCell()
@property (weak, nonatomic) IBOutlet UIImageView *iconView;
@property (weak, nonatomic) IBOutlet UILabel *nameLabel;
@property (weak, nonatomic) IBOutlet UIImageView *vipView;
@property (weak, nonatomic) IBOutlet UILabel *contentLabel;
@property (weak, nonatomic) IBOutlet UIImageView *pictureView;
@end
@implementation StatusCell
+(instancetype)cellWithTableView:(UITableView *)tableView
{
static NSString *ID = @"status";
StatusCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (cell == nil) {
cell = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self) owner:nil options:nil] lastObject];
}
return cell;
}
//设置label每行文字的最大宽度:为了保证计算出来的数值跟 真正显示出来的 效果一致
-(void)awakeFromNib
{
self.contentLabel.preferredMaxLayoutWidth = [UIScreen mainScreen].bounds.size.width - 20;
}
-(void)setStatus:(Status_M *)status
{
_status = status;
//判断是否是会员
if (status.isVip) {
self.nameLabel.textColor = [UIColor orangeColor];
self.vipView.hidden = NO;
}else{
self.nameLabel.textColor = [UIColor blackColor];
self.vipView.hidden = YES;
}
self.nameLabel.text = status.name;
self.iconView.image = [UIImage imageNamed:status.icon];
if (status.picture) {
self.pictureView.hidden = NO;
self.pictureView.image = [UIImage imageNamed:status.picture];
}else{
self.pictureView.hidden = YES;
}
self.contentLabel.text = status.text;
//强制布局
[self layoutIfNeeded];
//计算cell的高度
if (self.pictureView.hidden) {//没有配图
status.cellHeight = CGRectGetMaxY(self.contentLabel.frame) + 10;
}else{//配图
status.cellHeight = CGRectGetMaxY(self.pictureView.frame) + 10;
}
}
@end
设置cellheight
@interface StatusesViewController()
@property (strong, nonatomic) NSArray *statuses;
@end
@implementation StatusesViewController
-(NSArray *)statuses
{
if (_statuses == nil) {
//加载plist中的字典数组
NSString *path = [[NSBundle mainBundle] pathForResource:@"statuses.plist" ofType:nil];
NSArray *dictArray = [NSArray arrayWithContentsOfFile:path];
//字典数组-->模型数组
NSMutableArray *statusArray = [NSMutableArray array];
for (NSDictionary *dict in dictArray) {
Status_M *status = [Status_M statusWithDict: dict];
[statusArray addObject:status];
}
_statuses = statusArray;
}
return _statuses;
}
-(void)viewDidLoad
{
[super viewDidLoad];
}
#pragma mark data source
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.statuses.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
StatusCell *cell = [StatusCell cellWithTableView:tableView];
cell.status = self.statuses[indexPath.row];
return cell;
}
/**
* 返回每一行的高度
*/
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
Status_M *status = self.statuses[indexPath.row];
return status.cellHeight;
}
/**
* 返回每一行的估计高度
只要返回了估计高度,那么就会先条用tableView:cellForRowAtIndexPath:方法创建cell,再调用tableView heightForRowAtIndexPath:方法获取测cell的真实高度
*
*/
-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
return 200;
}
@end