一. 自定义UITableViewCell
在日常的编程中,系统提供的几种Cell 样式 往往不能满足我们的需求.所以需要我们给它进行自定义样式.
自定义Cell 就是创建一个UITableViewCell 的子类.把Cell 上的空间都封装在子类中,简化UIViewController上的代码 . 子视图空间添加到Cell 的ContentView 上面.
Cell 中声明一个Model类型的属性,ViewController中获取到Model对象后赋值给Cell 的Model属性
Cell 中重写Model 的setter 方法 把Model对象中的内容重新赋值给各个控件.
M和V之间不直接进行通信,C负责M和V之间进行通信.
通常我们会在
tableView:cellForRowAtIndexPath:
⽅方法中根据不同的
Model
来决定使⽤用什么类型的
cell
每种类型的
cell
要定义不同的重⽤用标识符
cell
重⽤用的时候会根据重⽤用标识从重⽤用队列中取⽤用哪种类型的
cell
自定义
Cell
的步骤
1. 创建一个继承自UITableViewCell 的类
2.
重写初始化方法
3.
在初始化方法中
把需要的视图添加在
self.contentView
上面
4.
未完待续
(
在
tableView
上面完成的
)
在
UITableView
里面把系统的
UItbleViewCell
换成我们定义好的
GodGirlCell
在Cell自定义中重写
- (
void
)setModel:(
GodGirlModel
*)model
{
if ( _model != model) {
[ _model retain ];
_model = [model retain ];
}
self . nameLabel . text = self . model . name ;
self . genderLabel . text = self . model . gender ;
self . hobbyLebel . text = self . model . hobby ;
self . phoneLabel . text = self . model . phoneNumber ;
{
if ( _model != model) {
[ _model retain ];
_model = [model retain ];
}
self . nameLabel . text = self . model . name ;
self . genderLabel . text = self . model . gender ;
self . hobbyLebel . text = self . model . hobby ;
self . phoneLabel . text = self . model . phoneNumber ;
}
在
UITableView
里面把系统的
UItbleViewCell
换成我们定义好的
GodGirlCell
- (
UITableViewCell
*)tableView:(
UITableView
*)tableView cellForRowAtIndexPath:(
NSIndexPath
*)indexPath
{
// static NSString *identifiter = @"GodGirlCell";
// GodGirlCell *cell = [tableView dequeueReusableCellWithIdentifier:identifiter];
// if (cell == nil) {
// cell = [[[GodGirlCell alloc]initWithStyle:(UITableViewCellStyleSubtitle) reuseIdentifier:identifiter]autorelease];
// }
// GodGirlCell *cell = [tableView dequeueReusableCellWithIdentifier:identifiter];
// if (cell == nil) {
// cell = [[[GodGirlCell alloc]initWithStyle:(UITableViewCellStyleSubtitle) reuseIdentifier:identifiter]autorelease];
// }
显示数据
1
// GodGirlModel *godGirl = self.array[indexPath.row];
// cell.godGirlimageview.image = [UIImage imageNamed:@"nvshen"];
// cell.nameLabel.text = godGirl.name;
// cell.hobbyLabel.text = godGirl.hobby;
// cell.phoneLabel.text = godGirl.phoneNumber;
// cell.godGirlimageview.image = [UIImage imageNamed:@"nvshen"];
// cell.nameLabel.text = godGirl.name;
// cell.hobbyLabel.text = godGirl.hobby;
// cell.phoneLabel.text = godGirl.phoneNumber;
显示数据
2
//
把
model
传进
Cell
内部进行赋值
//
把
model
进入
cell
内部
// 通过重写 model 的 set 方法
GodGirlModel *godGirl = self . array [indexPath. row ];
// 利用 model 的属性选择 显示不同的 cell
// 通过重写 model 的 set 方法
GodGirlModel *godGirl = self . array [indexPath. row ];
// 利用 model 的属性选择 显示不同的 cell
一个tableView 显示多种cell思路:
1. 创建多种不同布局的cell
2. 根据数据中特定的字段来判断要显示的哪种cell
3. 多种 Cell 的应用场景非常广
if ([godGirl.gender isEqualToString:@"
女
"
]) {
//
显示带图片的
cell
static NSString *identifiter = @"GodGirlCell" ; // 按照这个标示符 初始化这种 Cell 不要重复
GodGirlCell *cell = [tableView dequeueReusableCellWithIdentifier :identifiter];
if (cell == nil ) {
cell = [[[ GodGirlCell alloc ] initWithStyle :( UITableViewCellStyleSubtitle ) reuseIdentifier :identifiter] autorelease ];
}
// 显示数据
cell. model = godGirl;
return cell;
} else if ([godGirl. gender isEqualToString : @" 男 " ]) {
// 显示 不带图片的 cell
static NSString *identifiter = @"GodBoyCell" ;
GodBoyCell *cell = [tableView dequeueReusableCellWithIdentifier :identifiter];
if (cell == nil ) {
cell = [[[ GodBoyCell alloc ] initWithStyle :( UITableViewCellStyleSubtitle ) reuseIdentifier :identifiter] autorelease ];
}
cell. model = godGirl;
return cell;
static NSString *identifiter = @"GodGirlCell" ; // 按照这个标示符 初始化这种 Cell 不要重复
GodGirlCell *cell = [tableView dequeueReusableCellWithIdentifier :identifiter];
if (cell == nil ) {
cell = [[[ GodGirlCell alloc ] initWithStyle :( UITableViewCellStyleSubtitle ) reuseIdentifier :identifiter] autorelease ];
}
// 显示数据
cell. model = godGirl;
return cell;
} else if ([godGirl. gender isEqualToString : @" 男 " ]) {
// 显示 不带图片的 cell
static NSString *identifiter = @"GodBoyCell" ;
GodBoyCell *cell = [tableView dequeueReusableCellWithIdentifier :identifiter];
if (cell == nil ) {
cell = [[[ GodBoyCell alloc ] initWithStyle :( UITableViewCellStyleSubtitle ) reuseIdentifier :identifiter] autorelease ];
}
cell. model = godGirl;
return cell;
}
二. Cell 的自适应高度
1.
UILabel
*label = [[
UILabel
alloc
]
initWithFrame
:
CGRectMake
(
30
,
100
,
300
,
100
)];
label. backgroundColor = [ UIColor grayColor ];
[ self . window addSubview :label];
label. font = [ UIFont systemFontOfSize : 16 ];
NSString *string = @" 去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去 " ;
label. text = string;
label. backgroundColor = [ UIColor grayColor ];
[ self . window addSubview :label];
label. font = [ UIFont systemFontOfSize : 16 ];
NSString *string = @" 去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去去 " ;
label. text = string;
label.numberOfLines = 0;
计算文字的高度
该方法四个参数什么意思
Size
是之前定义的
label
的宽度
高度给一个到达不了的大数
NSStringDrawingUsesLineFragmentOrigin
按照文本的矩形区域
返回
高度
构建一个字体大小的字典
字体大小的字号要跟定义
Label
的一样
最后一个
nil
该方法计算
300
宽
30
字号的
Label
的高度
NSDictionary
*dic = [
NSDictionary
dictionaryWithObject
:[
UIFont
systemFontOfSize
:
16
]
forKey
:
NSFontAttributeName
];
CGRect frame = [string boundingRectWithSize : CGSizeMake ( 300 , 100000 ) options :( NSStringDrawingUsesLineFragmentOrigin ) attributes :dic context : nil ];
NSLog ( @"%f" , frame. size . height );
[label release ];
CGRect newFrame = label. frame ;
newFrame. size . height = frame. size . height ;
CGRect frame = [string boundingRectWithSize : CGSizeMake ( 300 , 100000 ) options :( NSStringDrawingUsesLineFragmentOrigin ) attributes :dic context : nil ];
NSLog ( @"%f" , frame. size . height );
[label release ];
CGRect newFrame = label. frame ;
newFrame. size . height = frame. size . height ;
label.frame = newFrame;
2.
NewsCell.m
- (
void
)dealloc
{
[ _titleLabel release ];
[ _summaryLabel release ];
[ _model release ];
[ _myImageView release ];
[ super dealloc ];
{
[ _titleLabel release ];
[ _summaryLabel release ];
[ _model release ];
[ _myImageView release ];
[ super dealloc ];
}
- (
void
)setModel:(
NewsModel
*)model
{
if ( _model != model) {
[ _model release ];
_model = [model retain ];
}
self . titleLabel . text = model. title ;
self . summaryLabel . text = model. summary ;
// 初始化的时候都走这里
// 防止 cell 被复用后状态消失
// 不过是创建出来的 还是按照 model 中状态标识 来选取需要的图片
if (model. isSelect == YES ) {
self . myImageView . image = [ UIImage imageNamed : @"select" ];
} else {
self . myImageView . image = [ UIImage imageNamed : @"cancel" ];
}
CGRect newFrame = self . summaryLabel . frame ;
newFrame. size . height = [ NewsCell cellWithModel :model];
self . summaryLabel . frame = newFrame;
}
- ( instancetype )initWithStyle:( UITableViewCellStyle )style reuseIdentifier:( NSString *)reuseIdentifier
{
self = [ super initWithStyle :style reuseIdentifier :reuseIdentifier];
if ( self ) {
[ self addSubViews ];
}
return self ;
}
- ( void )addSubViews
{
self . titleLabel = [[ UILabel alloc ] initWithFrame : CGRectMake ( 10 , 10 , 330 , 40 )];
self . titleLabel . backgroundColor = [ UIColor redColor ];
self . titleLabel . numberOfLines = 0 ;
self . titleLabel . font = [ UIFont systemFontOfSize : 16 ];
[ self . contentView addSubview : self . titleLabel ];
[ _titleLabel release ];
// 写一个 imageView
self . myImageView = [[ UIImageView alloc ] initWithFrame : CGRectMake ( 350 , 10 , 20 , 20 )];
self . myImageView . image = [ UIImage imageNamed : @"cancel" ];
[ self . contentView addSubview : self . myImageView ];
[ _myImageView release ];
self . summaryLabel = [[ UILabel alloc ] initWithFrame : CGRectMake ( 10 , 20 + self . titleLabel . frame . size . height , 350 , 130 )];
self . summaryLabel . numberOfLines = 0 ;
self . summaryLabel . font = [ UIFont systemFontOfSize : 16 ];
self . summaryLabel . backgroundColor = [ UIColor grayColor ];
[ self . contentView addSubview : self . summaryLabel ];
[ _summaryLabel release ];
}
// 通过一个字符串 返回一个高度
+ ( CGFloat )cellWithModel:( NewsModel *)model
{
// 计算字符串的高度
NSString *string = model. summary ;
NSDictionary *dic =[ NSDictionary dictionaryWithObject :[ UIFont systemFontOfSize : 16 ] forKey : NSFontAttributeName ];
CGRect frame = [string boundingRectWithSize : CGSizeMake ( 350 , 1000000 ) options :( NSStringDrawingUsesLineFragmentOrigin ) attributes :dic context : nil ];
{
if ( _model != model) {
[ _model release ];
_model = [model retain ];
}
self . titleLabel . text = model. title ;
self . summaryLabel . text = model. summary ;
// 初始化的时候都走这里
// 防止 cell 被复用后状态消失
// 不过是创建出来的 还是按照 model 中状态标识 来选取需要的图片
if (model. isSelect == YES ) {
self . myImageView . image = [ UIImage imageNamed : @"select" ];
} else {
self . myImageView . image = [ UIImage imageNamed : @"cancel" ];
}
CGRect newFrame = self . summaryLabel . frame ;
newFrame. size . height = [ NewsCell cellWithModel :model];
self . summaryLabel . frame = newFrame;
}
- ( instancetype )initWithStyle:( UITableViewCellStyle )style reuseIdentifier:( NSString *)reuseIdentifier
{
self = [ super initWithStyle :style reuseIdentifier :reuseIdentifier];
if ( self ) {
[ self addSubViews ];
}
return self ;
}
- ( void )addSubViews
{
self . titleLabel = [[ UILabel alloc ] initWithFrame : CGRectMake ( 10 , 10 , 330 , 40 )];
self . titleLabel . backgroundColor = [ UIColor redColor ];
self . titleLabel . numberOfLines = 0 ;
self . titleLabel . font = [ UIFont systemFontOfSize : 16 ];
[ self . contentView addSubview : self . titleLabel ];
[ _titleLabel release ];
// 写一个 imageView
self . myImageView = [[ UIImageView alloc ] initWithFrame : CGRectMake ( 350 , 10 , 20 , 20 )];
self . myImageView . image = [ UIImage imageNamed : @"cancel" ];
[ self . contentView addSubview : self . myImageView ];
[ _myImageView release ];
self . summaryLabel = [[ UILabel alloc ] initWithFrame : CGRectMake ( 10 , 20 + self . titleLabel . frame . size . height , 350 , 130 )];
self . summaryLabel . numberOfLines = 0 ;
self . summaryLabel . font = [ UIFont systemFontOfSize : 16 ];
self . summaryLabel . backgroundColor = [ UIColor grayColor ];
[ self . contentView addSubview : self . summaryLabel ];
[ _summaryLabel release ];
}
// 通过一个字符串 返回一个高度
+ ( CGFloat )cellWithModel:( NewsModel *)model
{
// 计算字符串的高度
NSString *string = model. summary ;
NSDictionary *dic =[ NSDictionary dictionaryWithObject :[ UIFont systemFontOfSize : 16 ] forKey : NSFontAttributeName ];
CGRect frame = [string boundingRectWithSize : CGSizeMake ( 350 , 1000000 ) options :( NSStringDrawingUsesLineFragmentOrigin ) attributes :dic context : nil ];
return frame.size.height;
}
NewsModel.m
- (
void
)dealloc
{
[ _title release ];
[ _summary release ];
[ super dealloc ];
}
// 防崩赋值方法
- ( void )setValue:( id )value forUndefinedKey:( NSString *)key
{
{
[ _title release ];
[ _summary release ];
[ super dealloc ];
}
// 防崩赋值方法
- ( void )setValue:( id )value forUndefinedKey:( NSString *)key
{
RootViewController.m
//
数据准备
- ( void )setUpData
{
NSString *path = [[ NSBundle mainBundle ] pathForResource : @"NewsData" ofType : @"plist" ];
NSDictionary *plistDic = [ NSDictionary dictionaryWithContentsOfFile :path];
NSArray *newsArray = [plistDic objectForKey : @"news" ];
// 数组一定要初始化
self . dataArray = [ NSMutableArray array ];
for ( NSDictionary *dic in newsArray) {
NewsModel *model = [[ NewsModel alloc ] init ];
model. isSelect = NO ;
[model setValuesForKeysWithDictionary :dic];
[ self . dataArray addObject :model];
[model release ];
}
NSLog ( @"%@" , self . dataArray );
}
- ( void )addTableView
{
UITableView *tableView = [[ UITableView alloc ] initWithFrame :[ UIScreen mainScreen ]. bounds style :( UITableViewStylePlain )];
tableView. delegate = self ;
tableView. dataSource = self ;
[ self . view addSubview :tableView];
[tableView release ];
}
- ( NSInteger )tableView:( UITableView *)tableView numberOfRowsInSection:( NSInteger )section
{
return self . dataArray . count ;
}
- ( UITableViewCell *)tableView:( UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath *)indexPath
{
static NSString *identifiter = @"cell" ;
NewsCell *cell = [tableView dequeueReusableCellWithIdentifier :identifiter];
if (cell == nil ) {
cell = [[ NewsCell alloc ] initWithStyle :( UITableViewCellStyleSubtitle ) reuseIdentifier :identifiter];
}
NewsModel *model = [ self . dataArray objectAtIndex :indexPath. row ];
cell. model = model;
return cell;
}
- ( CGFloat )tableView:( UITableView *)tableView heightForRowAtIndexPath:( NSIndexPath *)indexPath
{
// 取出 model 调用 cellWithModel 方法得到高度
NewsModel *model = [ self . dataArray objectAtIndex :indexPath. row ];
CGFloat SummaryHeight = [ NewsCell cellWithModel :model];
return 20 + 20 + 40 + SummaryHeight + 20 ;
}
// 点击触发的方法
- ( void )tableView:( UITableView *)tableView didSelectRowAtIndexPath:( NSIndexPath *)indexPath
{
// 获取要点击的 Cell
// 下面方法是获取自定义 cell 的方法
NewsCell *cell = ( NewsCell *)[tableView cellForRowAtIndexPath :indexPath];
// 不是自定义方法 就如下写
//UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NewsModel *model = [ self . dataArray objectAtIndex :indexPath. row ];
// 通过 model 的状态 更改图片
// 改变 model 的状态
model. isSelect = !model. isSelect ;
if (model. isSelect == YES ) {
cell. myImageView . image = [ UIImage imageNamed : @"select" ];
} else {
cell. myImageView . image = [ UIImage imageNamed : @"cancel" ];
}
NSLog ( @"%d" , model. isSelect );
- ( void )setUpData
{
NSString *path = [[ NSBundle mainBundle ] pathForResource : @"NewsData" ofType : @"plist" ];
NSDictionary *plistDic = [ NSDictionary dictionaryWithContentsOfFile :path];
NSArray *newsArray = [plistDic objectForKey : @"news" ];
// 数组一定要初始化
self . dataArray = [ NSMutableArray array ];
for ( NSDictionary *dic in newsArray) {
NewsModel *model = [[ NewsModel alloc ] init ];
model. isSelect = NO ;
[model setValuesForKeysWithDictionary :dic];
[ self . dataArray addObject :model];
[model release ];
}
NSLog ( @"%@" , self . dataArray );
}
- ( void )addTableView
{
UITableView *tableView = [[ UITableView alloc ] initWithFrame :[ UIScreen mainScreen ]. bounds style :( UITableViewStylePlain )];
tableView. delegate = self ;
tableView. dataSource = self ;
[ self . view addSubview :tableView];
[tableView release ];
}
- ( NSInteger )tableView:( UITableView *)tableView numberOfRowsInSection:( NSInteger )section
{
return self . dataArray . count ;
}
- ( UITableViewCell *)tableView:( UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath *)indexPath
{
static NSString *identifiter = @"cell" ;
NewsCell *cell = [tableView dequeueReusableCellWithIdentifier :identifiter];
if (cell == nil ) {
cell = [[ NewsCell alloc ] initWithStyle :( UITableViewCellStyleSubtitle ) reuseIdentifier :identifiter];
}
NewsModel *model = [ self . dataArray objectAtIndex :indexPath. row ];
cell. model = model;
return cell;
}
- ( CGFloat )tableView:( UITableView *)tableView heightForRowAtIndexPath:( NSIndexPath *)indexPath
{
// 取出 model 调用 cellWithModel 方法得到高度
NewsModel *model = [ self . dataArray objectAtIndex :indexPath. row ];
CGFloat SummaryHeight = [ NewsCell cellWithModel :model];
return 20 + 20 + 40 + SummaryHeight + 20 ;
}
// 点击触发的方法
- ( void )tableView:( UITableView *)tableView didSelectRowAtIndexPath:( NSIndexPath *)indexPath
{
// 获取要点击的 Cell
// 下面方法是获取自定义 cell 的方法
NewsCell *cell = ( NewsCell *)[tableView cellForRowAtIndexPath :indexPath];
// 不是自定义方法 就如下写
//UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NewsModel *model = [ self . dataArray objectAtIndex :indexPath. row ];
// 通过 model 的状态 更改图片
// 改变 model 的状态
model. isSelect = !model. isSelect ;
if (model. isSelect == YES ) {
cell. myImageView . image = [ UIImage imageNamed : @"select" ];
} else {
cell. myImageView . image = [ UIImage imageNamed : @"cancel" ];
}
NSLog ( @"%d" , model. isSelect );
}
}