通过代码自定义cell(cell的高度不一致)实现新浪微博界面
来源:互联网 发布:淘宝找代销货源 编辑:程序博客网 时间:2024/05/06 08:06
1.背景
当系统自带的cell和xib都不能满足需要的时候就需要自己用代码自定义cell
2.自定义cell的步骤
1.新建一个继承自UITableViewCell的类
2.重写initWithStyle:reuseIdentifier:方法
添加所有需要显示的子控件(不需要设置子控件的数据和frame, 子控件要添加到contentView中)
进行子控件一次性的属性设置(有些属性只需要设置一次, 比如字体\固定的图片)
3.提供2个模型
数据模型: 存放文字数据\图片数据
frame模型: 存放数据模型\所有子控件的frame\cell的高度
4.cell拥有一个frame模型(不要直接拥有数据模型)
5.重写frame模型属性的setter方法: 在这个方法中设置子控件的显示数据和frame
6.frame模型数据的初始化已经采取懒加载的方式(每一个cell对应的frame模型数据只加载一次)
3.通过代码自定义cell的案例,用代码自定义cell实现下面界面
4.具体实现
4.1plist文件
4.2代码实现
4.2.1模型类
(模型类MJStatus)
//// MJStatus.h#import <Foundation/Foundation.h>@interface MJStatus : NSObject@property (nonatomic, copy) NSString *text; // 内容@property (nonatomic, copy) NSString *icon; // 头像@property (nonatomic, copy) NSString *name; // 昵称@property (nonatomic, copy) NSString *picture; // 配图@property (nonatomic, assign) BOOL vip;- (instancetype)initWithDict:(NSDictionary *)dict;+ (instancetype)statusWithDict:(NSDictionary *)dict;@end
<pre name="code" class="objc">//// MJStatus.m#import "MJStatus.h"@implementation MJStatus- (instancetype)initWithDict:(NSDictionary *)dict{ if (self = [super init]) { [self setValuesForKeysWithDictionary:dict]; } return self;}+ (instancetype)statusWithDict:(NSDictionary *)dict{ return [[self alloc] initWithDict:dict];}@end
#import "MJStatus.h"<pre name="code" class="objc">//// MJStatusFrame.h//// 这个模型对象专门用来存放cell内部所有的子控件的frame数据 + cell的高度// 一个cell拥有一个MJStatusFrame模型//下面的属性都是 readonly的所以没有生成set方法,所以在set方法里面不能用点语法//有了MJStatusFrame就意味著一个cell拥有了MJStatusFrame就拥有了每一个子控件的frame 顺便拥有了MJStatus 模型#import <Foundation/Foundation.h>@class MJStatus;@interface MJStatusFrame : NSObject/** * 头像的frame ,结构体用assin */@property (nonatomic, assign, readonly) CGRect iconF;/** * 昵称的frame */@property (nonatomic, assign, readonly) CGRect nameF;/** * 会员图标的frame */@property (nonatomic, assign, readonly) CGRect vipF;/** * 正文的frame */@property (nonatomic, assign, readonly) CGRect textF;/** * 配图的frame */@property (nonatomic, assign, readonly) CGRect pictureF;/** * cell的高度 */@property (nonatomic, assign, readonly) CGFloat cellHeight;@property (nonatomic, strong) MJStatus *status; //只有拿到模型数据才能算这些属性的frame,readonly:在这个模型里面的frame属性别人不能乱改,只能访问@end
@implementation MJStatus- (instancetype)initWithDict:(NSDictionary *)dict{ if (self = [super init]) { [self setValuesForKeysWithDictionary:dict]; } return self;}+ (instancetype)statusWithDict:(NSDictionary *)dict{ return [[self alloc] initWithDict:dict];}@end
//// MJStatusFrame.m// 昵称的字体#define MJNameFont [UIFont systemFontOfSize:14]// 正文的字体#define MJTextFont [UIFont systemFontOfSize:15]#import "MJStatusFrame.h"#import "MJStatus.h"@implementation MJStatusFrame/** * 计算文字尺寸 * * @param text 需要计算尺寸的文字 * @param font 文字的字体 * @param maxSize 文字的最大尺寸 */- (CGSize)sizeWithText:(NSString *)text font:(UIFont *)font maxSize:(CGSize)maxSize{ NSDictionary *attrs = @{NSFontAttributeName : font}; return [text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;}- (void)setStatus:(MJStatus *)status //重写set方法,接收模型数据为本类的属性赋值{ _status = status; // 子控件之间的间距 CGFloat padding = 10; // 1.头像 CGFloat iconX = padding; CGFloat iconY = padding; CGFloat iconW = 30; CGFloat iconH = 30 _iconF = CGRectMake(iconX, iconY, iconW, iconH); //这些属性都是 readonly的所以没有生成set方法,所以在set方法里面不能用点语法,只能用 _iconF // 2.昵称 // 文字的字体 CGSize nameSize = [self sizeWithText:self.status.name font:MJNameFont maxSize:CGSizeMake(MAXFLOAT, MAXFLOAT)]; CGFloat nameX = CGRectGetMaxX(_iconF) + padding; CGFloat nameY = iconY + (iconH - nameSize.height) * 0.5; _nameF = CGRectMake(nameX, nameY, nameSize.width, nameSize.height); // 3.会员图标 CGFloat vipX = CGRectGetMaxX(_nameF) + padding; CGFloat vipY = nameY; CGFloat vipW = 14; CGFloat vipH = 14; _vipF = CGRectMake(vipX, vipY, vipW, vipH); // 4.正文 CGFloat textX = iconX; CGFloat textY = CGRectGetMaxY(_iconF) + padding; CGSize textSize = [self sizeWithText:self.status.text font:MJTextFont maxSize:CGSizeMake(300, MAXFLOAT)]; _textF = CGRectMake(textX, textY, textSize.width, textSize.height); // 5.配图 if (self.status.picture) {// 有配图 CGFloat pictureX = textX; CGFloat pictureY = CGRectGetMaxY(_textF) + padding; CGFloat pictureW = 100; CGFloat pictureH = 100; _pictureF = CGRectMake(pictureX, pictureY, pictureW, pictureH); _cellHeight = CGRectGetMaxY(_pictureF) + padding; } else { _cellHeight = CGRectGetMaxY(_textF) + padding; }}@end
4.2.2自定义cell
//// MJStatusCell.h#import <UIKit/UIKit.h>@class MJStatusFrame;@interface MJStatusCell : UITableViewCell@property (nonatomic, strong) MJStatusFrame *statusFrame;+ (instancetype)cellWithTableView:(UITableView *)tableView;@end
//// MJStatusCell.m// 昵称的字体#define MJNameFont [UIFont systemFontOfSize:14]// 正文的字体#define MJTextFont [UIFont systemFontOfSize:15]#import "MJStatusCell.h"#import "MJStatus.h"#import "MJStatusFrame.h"@interface MJStatusCell()/** * 头像 */@property (nonatomic, weak) UIImageView *iconView;/** * 昵称 */@property (nonatomic, weak) UILabel *nameView;/** * 会员图标 */@property (nonatomic, weak) UIImageView *vipView;/** * 正文 */@property (nonatomic, weak) UILabel *textView;/** * 配图 */@property (nonatomic, weak) UIImageView *pictureView;@end@implementation MJStatusCell/** * 构造方法(在初始化对象的时候会调用) * 一般在这个方法中添加需要显示的子控件 */- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{ self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { // 1.头像 UIImageView *iconView = [[UIImageView alloc] init]; [self.contentView addSubview:iconView]; self.iconView = iconView; // 2.昵称 UILabel *nameView = [[UILabel alloc] init]; nameView.font = MJNameFont; [self.contentView addSubview:nameView]; self.nameView = nameView; // 3.会员图标 UIImageView *vipView = [[UIImageView alloc] init]; vipView.image = [UIImage imageNamed:@"vip"]; [self.contentView addSubview:vipView]; self.vipView = vipView; // 4.正文 UILabel *textView = [[UILabel alloc] init]; textView.numberOfLines = 0; textView.font = MJTextFont; [self.contentView addSubview:textView]; self.textView = textView; // 5.配图 UIImageView *pictureView = [[UIImageView alloc] init]; [self.contentView addSubview:pictureView]; self.pictureView = pictureView; } return self;}/** * 在这个方法中设置子控件的frame和显示数据 */- (void)setStatusFrame:(MJStatusFrame *)statusFrame{ _statusFrame = statusFrame; // 1.设置数据 [self settingData]; // 2.设置frame [self settingFrame];}/** * 设置数据 */- (void)settingData{ // 微博数据 MJStatus *status = self.statusFrame.status; // 1.头像 self.iconView.image = [UIImage imageNamed:status.icon]; // 2.昵称 self.nameView.text = status.name; // 3.会员图标 if (status.vip) { self.vipView.hidden = NO; self.nameView.textColor = [UIColor redColor]; } else { self.vipView.hidden = YES; self.nameView.textColor = [UIColor blackColor]; } // 4.正文 self.textView.text = status.text; // 5.配图 if (status.picture) { // 有配图 self.pictureView.hidden = NO; self.pictureView.image = [UIImage imageNamed:status.picture]; } else { // 没有配图 self.pictureView.hidden = YES; }}/** * 计算文字尺寸 * * @param text 需要计算尺寸的文字 * @param font 文字的字体 * @param maxSize 文字的最大尺寸 */- (CGSize)sizeWithText:(NSString *)text font:(UIFont *)font maxSize:(CGSize)maxSize{ NSDictionary *attrs = @{NSFontAttributeName : font}; return [text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;}/** * 设置frame */- (void)settingFrame{ // 1.头像 self.iconView.frame = self.statusFrame.iconF; // 2.昵称 self.nameView.frame = self.statusFrame.nameF; // 3.会员图标 self.vipView.frame = self.statusFrame.vipF; // 4.正文 self.textView.frame = self.statusFrame.textF; // 5.配图 if (self.statusFrame.status.picture) {// 有配图 self.pictureView.frame = self.statusFrame.pictureF; }}+ (instancetype)cellWithTableView:(UITableView *)tableView{ static NSString *ID = @"status"; MJStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; if (cell == nil) { cell = [[MJStatusCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID]; } return cell;}@end
4.2.3控制器类
//// MJViewController.m#import "MJViewController.h"#import "MJStatus.h"#import "MJStatusFrame.h"#import "MJStatusCell.h"@interface MJViewController ()//@property (nonatomic, strong) NSArray *statuses;/** * 存放所有cell的frame模型数据 */@property (nonatomic, strong) NSArray *statusFrames;@end@implementation MJViewController- (void)viewDidLoad{ [super viewDidLoad]; // self.tableView.rowHeight = 400;}- (NSArray *)statusFrames{ if (_statusFrames == nil) { // 初始化 // 1.获得plist的全路径 NSString *path = [[NSBundle mainBundle] pathForResource:@"statuses.plist" ofType:nil]; // 2.加载数组 NSArray *dictArray = [NSArray arrayWithContentsOfFile:path]; // 3.将dictArray里面的所有字典转成模型对象,放到新的数组中 NSMutableArray *statusFrameArray = [NSMutableArray array]; for (NSDictionary *dict in dictArray) { // 3.1.创建MJStatus模型对象 MJStatus *status = [MJStatus statusWithDict:dict]; // 3.2.创建MJStatusFrame模型对象 MJStatusFrame *statusFrame = [[MJStatusFrame alloc] init]; statusFrame.status = status; //set方法 // 3.2.添加模型对象到数组中 [statusFrameArray addObject:statusFrame]; } // 4.赋值 _statusFrames = statusFrameArray; } return _statusFrames;}- (BOOL)prefersStatusBarHidden{ return YES;}#pragma mark - 实现数据源方法- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return self.statusFrames.count; //多少行}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ // 1.创建cell MJStatusCell *cell = [MJStatusCell cellWithTableView:tableView]; // 2.在这个方法算好了cell的高度 cell.statusFrame = self.statusFrames[indexPath.row]; // 3.返回cell return cell;}#pragma mark - 实现代理方法- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ // 取出这行对应的frame模型 MJStatusFrame *statusFrame = self.statusFrames[indexPath.row]; return statusFrame.cellHeight;}@end
- 通过代码自定义cell(cell的高度不一致)实现新浪微博界面
- 通过代码自定义cell (cell的高度不一致)的步骤:
- 通过代码自定义cell(cell的高度不一致)的步骤
- 通过代码自定义cell(cell的高度不一致)
- 通过代码自定义cell(cell的高度不一致)
- 通过代码自定义cell(cell的高度不一致)
- 通过代码自定义cell(cell的高度不一致)
- 通过代码自定义cell(cell的高度不一致)
- 通过代码自定义cell(cell的高度不一致)
- 通过代码自定义cell,cell的高度不一致
- 通过代码自定义cell(cell的高度不一致)
- 通过代码自定义cell(cell的高度不一致)
- 通过代码自定义cell(cell的高度不一致)
- 通过代码自定义cell(cell的高度不一致)
- 通过代码自定义cell(cell的高度不一致)
- 总结-通过代码自定义cell(cell的高度不一致)
- 通过代码自定义cell(cell的高度不一致)
- 通过代码自定义cell(cell的高度不一致)
- STM32F10X SPI操作flash MX25L64读写数据
- 【转载】OceanBase架构介绍
- 关于oracle可以本地访问不能远程被访问的问题解决思路
- 创业经历
- Mysql命令行下备份恢复数据库数据操作
- 通过代码自定义cell(cell的高度不一致)实现新浪微博界面
- Java 中Iterator 、Vector、ArrayList、List 使用深入剖析
- ubuntu安装GD库支持
- 【四圣龙神录的编程教室】第3章、使用全局变量看看吧
- SPI flash学习
- ddwrt+wifidog搭建热点认证系统(无线路由器web认证)
- UIButton详解
- hdu oj 2006
- wifidog+authpuppy认证页面的配置