您的位置:首页 > 产品设计 > UI/UE

iOS中的UITableView自定义Cell(模仿新浪微博)

2016-05-23 00:00 477 查看


定义一个KCStatusTableViewCell实现UITableViewCell,一般实现自定义UITableViewCell需要分为两步:第一初始化控件;第二设置数据,重新设置控件frame。原因就是自定义Cell一般无法固定高度,很多时候高度需要随着内容改变。此外由于在单元格内部是无法控制单元格高度的,因此一般会定义一个高度属性用于在UITableView的代理事件中设置每个单元格高度。

首先看一下微博模型KCStatus,这个模型主要的方法就是根据plist字典内容生成微博对象:

KCStatus.h

[code=language-objectivec]#import <Foundation/Foundation.h>

//微博模型KCStatus,这个模型主要的方法就是根据plist字典内容生成微博对象:

@interface KCStatus : NSObject

#pragma mark - 属性
@property (nonatomic,assign) long long Id;//微博ID
@property (nonatomic,copy) NSString *profileImageUrl;//用户头像
@property (nonatomic,copy) NSString *userName;//用户名称
@property (nonatomic,copy) NSString *mbtype;//会员类型
@property (nonatomic,copy) NSString *createdAt;//创建时间
@property (nonatomic,copy) NSString *source;//设备来源
@property (nonatomic,copy) NSString *text;//微博内容

#pragma mark - 方法
#pragma mark 根据字典初始化微博对象
-(KCStatus *)initWithDictionary:(NSDictionary *)dic;

#pragma mark 初始化微博对象(静态方法)
+(KCStatus *)statusWithDictionary:(NSDictionary *)dic;

@end


KCStatus.m

[code=language-objectivec]#import "KCStatus.h"

@implementation KCStatus

#pragma mark 根据字典初始化微博对象
-(KCStatus *)initWithDictionary:(NSDictionary *)dic{

if (self = [super init]) {

self.Id = [dic[@"id"] longLongValue];
self.profileImageUrl = dic[@"profileImageUrl"];
self.userName = dic[@"userName"];
self.mbtype = dic[@"mbtype"];
self.createdAt = dic[@"createdAt"];
self.source = dic[@"source"];
self.text = dic[@"text"];

}

return self;

}

#pragma mark 初始化微博对象(静态方法)
+(KCStatus *)statusWithDictionary:(NSDictionary *)dic{

KCStatus *status = [[KCStatus alloc]initWithDictionary:dic];

return status;
}

//使用 stringWithFormat 拼接设备来源
-(NSString *)source{
return [NSString stringWithFormat:@"来自 %@", _source];
}

@end


然后看一下自定义的Cell

KCStatusTableViewCell.h

[code=language-objectivec]#import <UIKit/UIKit.h>
//#import "KCStatus.h"

// import会包含这个类的所有信息,包括实体变量和方法,而@class只是告诉编译器,其后面声明的名称是类的名称,至于这些类是如何定义的,暂时不用考虑,后面会再告诉你。
@class KCStatus;

//自定义的cell
@interface KCStatusTableViewCell : UITableViewCell

#pragma mark 微博对象
@property (nonatomic, strong) KCStatus *status;

#pragma mark 单元格高度
@property (assign, nonatomic) CGFloat height;

@end


KCStatusTableViewCell.m

[code=language-objectivec]#import "KCStatusTableViewCell.h"
#import "KCStatus.h"

#define KCColor(r,g,b) [UIColor colorWithHue:r/255.0 saturation:g/255.0 brightness:b/255.0 alpha:1] //颜色宏定义
#define kStatusTableViewCellControlSpacing 10 //控件间距
#define kStatusTableViewCellBackgroundColor KCColor(251,251,251)
#define kStatusGrayColor KCColor(50,50,50)
#define kStatusLightGrayColor KCColor(120,120,120)

#define kStatusTableViewCellAvatarWidth 40 //头像宽度
#define kStatusTableViewCellAvatarHeight kStatusTableViewCellAvatarWidth
#define kStatusTableViewCellUserNameFontSize 14
#define kStatusTableViewCellMbTypeWidth 13 //会员图标宽度
#define kStatusTableViewCellMbTypeHeight kStatusTableViewCellMbTypeWidth
#define kStatusTableViewCellCreateAtFontSize 12
#define kStatusTableViewCellSourceFontSize 12
#define kStatusTableViewCellTextFontSize 14

@interface KCStatusTableViewCell(){

UIImageView *cellAvatar;//用户头像
UIImageView *cellMbType;//会员类型
UILabel *cellUserName;//用户名称
UILabel *cellCreateAt;//创建时间
UILabel *cellSource;//设备来源
UILabel *cellText;//微博内容

}

@end

@implementation KCStatusTableViewCell

-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{

self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self initSubView];
}

return self;

}

#pragma mark 初始化视图
-(void)initSubView{

//头像控件
cellAvatar = [[UIImageView alloc]init];
[self.contentView addSubview:cellAvatar];

//用户名
cellUserName = [[UILabel alloc]init];
cellUserName.textColor = kStatusGrayColor;
cellUserName.font = [UIFont systemFontOfSize:kStatusTableViewCellUserNameFontSize];
[self.contentView addSubview:cellUserName];

//会员类型
cellMbType = [[UIImageView alloc]init];
[self.contentView addSubview:cellMbType];

//日期
cellCreateAt = [[UILabel alloc]init];
cellCreateAt.textColor = kStatusLightGrayColor;
cellCreateAt.font = [UIFont systemFontOfSize:kStatusTableViewCellCreateAtFontSize];
[self.contentView addSubview:cellCreateAt];

//设备
cellSource = [[UILabel alloc]init];
cellSource.textColor = kStatusLightGrayColor;
cellSource.font = [UIFont systemFontOfSize:kStatusTableViewCellSourceFontSize];
[self.contentView addSubview:cellSource];

//内容
cellText = [[UILabel alloc]init];
cellText.textColor = kStatusGrayColor;
cellText.font = [UIFont systemFontOfSize:kStatusTableViewCellTextFontSize];
cellText.numberOfLines=0;
//    cellText.lineBreakMode=NSLineBreakByWordWrapping;
[self.contentView addSubview:cellText];

}

#pragma mark 设置微博
-(void)setStatus:(KCStatus *)status{

//设置头像大小和位置
CGFloat avatarX=10,avatarY=10;
CGRect avatarRect=CGRectMake(avatarX, avatarY, kStatusTableViewCellAvatarWidth, kStatusTableViewCellAvatarHeight);
cellAvatar.image=[UIImage imageNamed:status.profileImageUrl];
cellAvatar.frame=avatarRect;

//设置会员图标大小和位置
CGFloat userNameX= CGRectGetMaxX(cellAvatar.frame)+kStatusTableViewCellControlSpacing ;
CGFloat userNameY=avatarY;
//根据文本内容取得文本占用空间大小
CGSize userNameSize=[status.userName sizeWithAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:kStatusTableViewCellUserNameFontSize]}];
CGRect userNameRect=CGRectMake(userNameX, userNameY, userNameSize.width,userNameSize.height);
cellUserName.text=status.userName;
cellUserName.frame=userNameRect;

//设置会员图标大小和位置
CGFloat mbTypeX=CGRectGetMaxX(cellUserName.frame)+kStatusTableViewCellControlSpacing;
CGFloat mbTypeY=avatarY;
CGRect mbTypeRect=CGRectMake(mbTypeX, mbTypeY, kStatusTableViewCellMbTypeWidth, kStatusTableViewCellMbTypeHeight);
cellMbType.image=[UIImage imageNamed:status.mbtype];
cellMbType.frame=mbTypeRect;

//设置发布日期大小和位置
CGSize createAtSize=[status.createdAt sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kStatusTableViewCellCreateAtFontSize]}];
CGFloat createAtX=userNameX;
CGFloat createAtY=CGRectGetMaxY(cellAvatar.frame)-createAtSize.height;
CGRect createAtRect=CGRectMake(createAtX, createAtY, createAtSize.width, createAtSize.height);
cellCreateAt.text=status.createdAt;
cellCreateAt.frame=createAtRect;

//设置设备信息大小和位置
CGSize sourceSize=[status.source sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:kStatusTableViewCellSourceFontSize]}];
CGFloat sourceX=CGRectGetMaxX(cellCreateAt.frame)+kStatusTableViewCellControlSpacing;
CGFloat sourceY=createAtY;
CGRect sourceRect=CGRectMake(sourceX, sourceY, sourceSize.width,sourceSize.height);
cellSource.text=status.source;
cellSource.frame=sourceRect;

//设置微博内容大小和位置
CGFloat textX=avatarX;
CGFloat textY=CGRectGetMaxY(cellAvatar.frame)+kStatusTableViewCellControlSpacing;
CGFloat textWidth=self.frame.size.width-kStatusTableViewCellControlSpacing*2;
CGSize textSize=[status.text boundingRectWithSize:CGSizeMake(textWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:kStatusTableViewCellTextFontSize]} context:nil].size;
CGRect textRect=CGRectMake(textX, textY, textSize.width, textSize.height);
cellText.text=status.text;
cellText.frame=textRect;

_height=CGRectGetMaxY(cellText.frame)+kStatusTableViewCellControlSpacing;

}

- (void)awakeFromNib {
// Initialization code
}

#pragma mark 重写选择事件,取消选中
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];

// Configure the view for the selected state
}

@end

这是我们自定义Cell这个例子的核心,自定义Cell分为两个步骤:首先要进行各种控件的初始化工作,这个过程中只要将控件放到Cell的View中同时设置控件显示内容的格式(字体大小、颜色等)即可;然后在数据对象设置方法中进行各个控件的布局(大小、位置)。在代码中有几点需要重点提示大家:

对于单行文本数据的显示调用- (CGSize)sizeWithAttributes:(NSDictionary *)attrs;方法来得到文本宽度和高度。

对于多行文本数据的显示调用- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(NSDictionary *)attributes context:(NSStringDrawingContext *)context ;方法来得到文本宽度和高度;同时注意在此之前需要设置文本控件的numberOfLines属性为0。

通常我们会在自定义Cell中设置一个高度属性,用于外界方法调用,因为Cell内部设置Cell的高度是没有用的,UITableViewCell在初始化时会重新设置高度。

最后我们看一下自定义Cell的使用过程:

KCStatusViewController.h

[code=language-objectivec]#import <UIKit/UIKit.h>

@interface KCStatusViewController : UIViewController

@end


KCStatusViewController.m

[code=language-objectivec]#import "KCStatusViewController.h"
#import "KCStatus.h"
#import "KCStatusTableViewCell.h"

@interface KCStatusViewController ()<UITableViewDelegate,UITableViewDataSource,UIAlertViewDelegate>{

UITableView *myTableView;
NSMutableArray *statusArray;
NSMutableArray *statusCellsArray;//存储cell,用于计算高度

}

@end

@implementation KCStatusViewController

- (void)viewDidLoad {
[super viewDidLoad];

//初始化数据
[self initData];

//创建一个分组样式的UITableView
myTableView = [[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStyleGrouped];

//设置数据源,注意实现UITableViewDataSource协议
myTableView.dataSource = self;
//设置代理
myTableView.delegate = self;

[self.view addSubview:myTableView];

}

#pragma mark 加载数据
-(void)initData{

NSString *path = [[NSBundle mainBundle] pathForResource:@"StatusInfo" ofType:@"plist"];
NSArray *array = [NSArray arrayWithContentsOfFile:path];

statusArray = [[NSMutableArray alloc]init];
statusCellsArray = [[NSMutableArray alloc]init];

[array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

[statusArray addObject:[KCStatus statusWithDictionary:obj]];
KCStatusTableViewCell *cell = [[KCStatusTableViewCell alloc]init];
[statusCellsArray addObject:cell];

}];

}

#pragma mark - 数据源方法

#pragma mark 返回分组数
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{

return 1;
}

#pragma mark 返回每组行数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

return statusArray.count;

}

#pragma mark 返回每行的单元格(cell上面展示的内容)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

static NSString *cellIdentifier = @"UITableViewCellIdentifierKey1";
KCStatusTableViewCell *cell;
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

if (!cell) {

cell = [[KCStatusTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];

}

/**
*  这个类中需要重点强调一下:Cell的高度需要重新设置(前面说过无论Cell内部设置多高都没有用,需要重新设置),这里采用的方法是首先创建对应的Cell,然后在- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;方法中设置微博数据计算高度通知UITableView。
*/

//在此设置微博,以便重新布局
KCStatus *status = statusArray[indexPath.row];
cell.status = status;
return cell;

}

#pragma mark - 代理方法

#pragma mark 重新设置单元格高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{

//    KCStatusTableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
KCStatusTableViewCell *cell = statusCellsArray[indexPath.row];
cell.status = statusArray[indexPath.row];

return cell.height;

}

#pragma mark 重写状态样式方法
-(UIStatusBarStyle)preferredStatusBarStyle{

return UIStatusBarStyleLightContent;

}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/

@end


大神地址:http://www.cnblogs.com/kenshincui/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: