一、自定义cell详细步骤介绍
自定义cell,控件不固定(比如微博)
1.新建一个继承自UITableViewCell的类重写initWithStyle:reuseIdentifier:方法
添加所有需要显示的子控件(不需要设置子控件的数据和frame, 子控件要添加到contentView中)
进行子控件一次性的属性设置(有些属性只需要设置一次, 比如字体\固定的图片) -- 初始化 ,添加到contentView中,赋值,设置一次性属性(比如字体,vipImage)
2.提供2个模型
数据模型: 存放文字数据\图片数据 -- 和Cell 中的控件相对应,同时和json中数据相对应,有用的数据都存储
frame模型: 存放数据模型\所有子控件的frame\cell的高度 -- 在setModel中设置各个控件的frame,并计算cellHeight;
3.cell拥有一个frame模型(不要直接拥有数据模型) -- 在setModelFrame中settingData 和 settingFrame;
4.在TableViewController提供一个NSArray *modelFrames; 在setting方法中获取网络数据,
-- statusFrame.status = status 在settingStatus中设置status的frame,在HomeViewController中从服务器获取status数据,
5.接下来 数据源 代理(cellHeight)
二、自定义cell最终总结
第一步 新建cell,重写initWithStyle:reuseIdentifier:
第二步 创建Status 和 StatusFrame 模型
Status中的属性和cell中的控件相对应
StatusFrame中装各个控件的 frame 和 cellHeight
第三步 重写setStatus 和 setStatusFrame 方法
重写setStatus,计算各控件 frame 和 cellHeight
重写setStatusFrame方法,settingData 和 settingFrame
第四步 获取Status数据,写数据源和代理方法
ps:cell初始化的时候,初始化所有子控件
对于不一定显示的控件,我们在settingData的时候根据Status中有无此数据来设置该控件是否显示
将其余步骤都完成之后,在计算frame这一步我们可以一个个来计算,减少出错率!
获取到Status数据时,我们可以先NSLog看一看,在转模型,装到Frame中
整个WBTableViewController相当于:我们将33个双色球放到了大箱子中,用到第一个就取出第一个,用到第二个就取第二个。提高了性能,手机界面不会出现卡顿现象
三、demo奉上!
第一步 新建cell,重写initWithStyle:reuseIdentifier:
#import "WBStatusCell.h"
@interface WBStatusCell ()
// 头像
@property(nonatomic,weak)UIImageView *iconImage;
// 昵称
@property(nonatomic,weak)UILabel *nameLable;
// vip
@property(nonatomic,weak)UIImageView *vipImage;
// 正文
@property(nonatomic,weak)UILabel *contentLable;
// 图片
@property(nonatomic,weak)UIImageView *photoImage;
@end
@implementation WBStatusCell
+ (instancetype)cellWithTableView:(UITableView *)tableView{
static NSString *ID = @"status";
WBStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if(cell == nil){
cell = [[WBStatusCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
}
return cell;
}
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// 头像
UIImageView *iconImage = [[UIImageView alloc] init]; // 在这里我们初始化控件,添加到contentView中,赋值,设置一次性属性(比如字体,vipImage)
[self.contentView addSubview:iconImage];
self.iconImage = iconImage;
// 昵称
UILabel *nameLable = [[UILabel alloc] init];
[self.contentView addSubview:nameLable];
nameLable.font = BJNameFont;
self.nameLable = nameLable;
// vip
UIImageView *vipImage = [[UIImageView alloc] init];
[self.contentView addSubview:vipImage];
vipImage.image = [UIImage imageNamed:@"vip"];
self.vipImage = vipImage;
// 正文
UILabel *contentLable = [[UILabel alloc] init];
[self.contentView addSubview:contentLable];
contentLable.font = BJContentFont;
contentLable.numberOfLines = 0;
self.contentLable = contentLable;
// 图片
UIImageView *photoImage = [[UIImageView alloc] init];
[self.contentView addSubview:photoImage];
self.photoImage = photoImage;
}
return self;
}
第二步 创建Status 和 StatusFrame 模型
Status的属性是和cell中控件对应的
//
// WBStatus.h
// WB
//
// Created by hubaojie on 15-7-14.
// Copyright (c) 2015年 hubaojie. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface WBStatus : NSObject
// 头像
@property(nonatomic,copy)NSString *icon;
// 昵称
@property(nonatomic,copy)NSString *name;
// vip
@property(nonatomic,assign)BOOL vip;
// 正文
@property(nonatomic,copy)NSString *content;
// 图片
@property(nonatomic,copy)NSString *photo;
//
+ (instancetype)statusWithDict:(NSDictionary *)dict;
- (instancetype)initWithDict:(NSDictionary *)dict;
@end
StatusFrame中装各个控件的 frame 和 cellHeight
//
// WBStatusFrame.h
// WB
//
// Created by hubaojie on 15-7-14.
// Copyright (c) 2015年 hubaojie. All rights reserved.
//
#define BJNameFont [UIFont systemFontOfSize:14]
#define BJContentFont [UIFont systemFontOfSize:14]
#import <UIKit/UIKit.h>
#import "WBStatus.h"
@interface WBStatusFrame : NSObject
@property(nonatomic,strong)WBStatus *status;
// 头像
@property(nonatomic,assign,readonly)CGRect iconImageF; // 控件的尺寸不允许别人随便更改,所以这里采取了readonly
// 昵称
@property(nonatomic,assign,readonly)CGRect nameLableF;
// vip
@property(nonatomic,assign,readonly)CGRect vipImageF;
// 正文
@property(nonatomic,assign,readonly)CGRect contentLableF;
// 图片
@property(nonatomic,assign,readonly)CGRect photoImageF;
// cellHeight
@property(nonatomic,assign,readonly)CGFloat cellHeight; // 特别:设置cell高度
@end
第三步 重写setStatus 和 setStatusFrame 方法
重写setStatus,计算各控件 frame 和 cellHeight
//
// WBStatusFrame.m
// WB
//
// Created by hubaojie on 15-7-14.
// Copyright (c) 2015年 hubaojie. All rights reserved.
//
#import "WBStatusFrame.h"
@implementation WBStatusFrame
/**
* 重写setStatus方法,设置控件尺寸
*
* @param status <#status description#>
*/
- (void)setStatus:(WBStatus *)status{
_status = status;
CGFloat padding = 10;
// 头像
CGFloat iconX = padding;
CGFloat iconY = padding;
CGFloat iconW = 30;
CGFloat iconH = 30;
_iconImageF = CGRectMake(iconX, iconY, iconW, iconH);
// 昵称
CGFloat nameX = CGRectGetMaxX(_iconImageF) + padding;
CGFloat nameH = [self.status.name sizeWithFont:BJNameFont].height;
CGFloat nameY = padding + (iconH - nameH) / 2;
CGFloat nameW = [self.status.name sizeWithFont:BJNameFont].width;
_nameLableF = CGRectMake(nameX, nameY, nameW, nameH);
// vip
CGFloat vipX = CGRectGetMaxX(_nameLableF) +padding;
CGFloat vipY = nameY;
CGFloat vipW = 14;
CGFloat vipH = 14;
_vipImageF = CGRectMake(vipX, vipY, vipW, vipH);
// 正文
CGFloat contentX = padding;
CGFloat contentY = CGRectGetMaxY(_vipImageF) + padding*2;
CGSize contentSize = [self.status.content boundingRectWithSize:CGSizeMake(300, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:BJContentFont} context:nil].size;
// CGSize contentSize = [self.status.content sizeWithFont:BJContentFont];
_contentLableF = (CGRect){{contentX,contentY},contentSize};
// 图片
if(self.status.photo){
CGFloat photoX = padding;
CGFloat photoY = CGRectGetMaxY(_contentLableF) + padding*2;
CGFloat photoW = 100;
CGFloat photoH = 100;
_photoImageF = CGRectMake(photoX, photoY, photoW, photoH);
_cellHeight = CGRectGetMaxY(_photoImageF) + padding;
}else{
_cellHeight = CGRectGetMaxY(_contentLableF) + padding;
}
// cellHeight
}
@end
重写setStatusFrame方法,设置frame和data
//
// WBStatusCell.h
// WB
//
// Created by hubaojie on 15-7-14.
// Copyright (c) 2015年 hubaojie. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "WBStatusFrame.h"
@interface WBStatusCell : UITableViewCell
//
@property(nonatomic,strong)WBStatusFrame *statusFrame;
+ (instancetype)cellWithTableView:(UITableView *)tableView;
@end
- (void)setStatusFrame:(WBStatusFrame *)statusFrame{
_statusFrame = statusFrame;
// 设置数据
[self settingData];
// 设置尺寸
[self settingFrame];
}
/**
* 设置数据
*/
- (void)settingData{
WBStatus *status = self.statusFrame.status;
// 头像
self.iconImage.image = [UIImage imageNamed:status.icon];
// 昵称
self.nameLable.text = status.name;
// vip
if(status.vip){
self.nameLable.textColor = [UIColor redColor]; // 在settingData中判断控件是否显示
self.vipImage.hidden = NO;
}else{
self.nameLable.textColor = [UIColor blackColor];
self.vipImage.hidden = YES;
}
// 正文
self.contentLable.text = status.content;
// 图片
if(status.photo)
self.photoImage.image = [UIImage imageNamed:status.photo];
}
/**
* 设置尺寸
*/
- (void)settingFrame{
// 头像
self.iconImage.frame = self.statusFrame.iconImageF;
// 昵称
self.nameLable.frame = self.statusFrame.nameLableF;
// vip
self.vipImage.frame = self.statusFrame.vipImageF;
// 正文
self.contentLable.frame = self.statusFrame.contentLableF;
// 图片
self.photoImage.frame = self.statusFrame.photoImageF;
}
第四步 获取Status数据,写数据源和代理方法
//
// WBViewController.m
// WB
//
// Created by hubaojie on 15-7-14.
// Copyright (c) 2015年 hubaojie. All rights reserved.
//
#import "WBViewController.h"
#import "WBStatus.h"
#import "WBStatusFrame.h"
#import "WBStatusCell.h"
@interface WBViewController ()
@property(nonatomic,strong)NSArray *statusFrames;
@end
@implementation WBViewController
- (NSArray *)statusFrames{
if(_statusFrames == nil){
NSString *path = [[NSBundle mainBundle] pathForResource:@"statuses.plist" ofType:nil];
NSArray *dictArray = [NSArray arrayWithContentsOfFile:path];
// NSLog(@"%@",dictArray);
NSMutableArray *statusFrameArray = [NSMutableArray array];
for (NSDictionary *dict in dictArray) {
WBStatusFrame *statusFrame = [[WBStatusFrame alloc] init];
WBStatus *status = [WBStatus statusWithDict:dict];
statusFrame.status = status; // 这一步关键:采用懒加载的方式设置statusFrame中的 数据 和 frame
[statusFrameArray addObject:statusFrame];
}
_statusFrames = statusFrameArray;
}
return _statusFrames;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.contentInset = UIEdgeInsetsMake(10, 0, 0, 0);
}
// 整个WBTableViewController相当于:我们
将33个双色球放到了大箱子中,用到第一个就取出第一个,用到第二个就取第二个。提高了性能,手机界面不会出现卡顿现象
#pragma mark - Table view data source 。。
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.statusFrames.count; // 采用懒加载的方式事先读取完数据
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// 1、创建cell
WBStatusCell *cell = [WBStatusCell cellWithTableView:tableView];
// 2、设置cell数据
cell.statusFrame = self.statusFrames[indexPath.row]; // 用到哪个数据 就 调用哪个数据
// 3、返回cell
return cell;
}
// 设置cell高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
WBStatusFrame *statusFrame = self.statusFrames[indexPath.row];
return statusFrame.cellHeight;
}
// 点击cell做出的操作
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
// 选中后取消选中
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}
@end