iOS开发UI篇—以微博界面为例使用纯代码自定义cell程序编码全过程(二)
2014-11-02 15:40
941 查看
iOS开发UI篇—以微博界面为例使用纯代码自定义cell程序编码全过程(二)
一、需要改进的地方
还需改进的地方:cell的高度需要根据每条微博的数据进行动态设置。
设置cell的高度可以有两种方式,一种是通过rowheight属性来进行设置,一种是通过代理来进行设置。通过属性设置适用于每行的高度一致,使用代理适用于每行的高度不一致的情况。
二、实现思路
在这个应用中,每个cell的高度是根据内容来确定的,所以在这里我们通过代理来设置cell的高度。
获取到图片最大的Y值或者是文字最大的Y值,在cell中设置一个新的变量。
判断一下,如果有配图,则高度等于配图的高度+间隙的高度,如果没有配图那么高度等于文字的高度+间隙的高度。
在自定义cell的setting frame方法中计算出行高,而要在主控制器中进行使用,怎么办才能拿到数据?
计算行高的方法最终是由cellforrow(setweibo->settingframe->计算行高)调用的,如果要拿到行高的话,需要先调用cellforrow这个方法。
查看cellforrow和heughtforrow这两个方法是谁先调用,结果显示是heiforrow先调用。
拿不到计算的行高?怎么办?
让它在计算heightforrow之前就计算出行高。计算行高,依赖于其他控件中的位置,位置依赖于模型中的数据。
拿到模型数据,就可以计算出高度。
那么在哪里可以拿到数据模型呢?
在懒加载中创建模型,就可以拿到模型,计算所有控件的frame,在懒加载中就可以获得行高。
拿到模型后可以计算出5个frame,那么就使用一个模型,把着5个frame保存起来,将来一个自定义的cell就对应一个frame模型。
新建一个类,继承自nsobject,这个类专门用来保存每一行数据的frame。在类中创建5个对应的frame属性,(CGRECT)以及一个行高。添加一个模型数据,当别人给我一个模型数据的时候,我就可以通过重写set方法,设置模型数据的frame.
把之前的frame计算方法拷贝过去。(为什么?)
在懒加载方法中,根据模型数据创建frame模型,往数组里面添加的时候添加frame模型,此时该数组中既有所有的数据模型,又拥有对应的frame。
在代理方法中,获取到当前索引对应的frame。
三、实现代码
1.项目文件结构
2.代码
模型部分
TXStatus.h文件
TXStatus.m文件
视图部分
TXStatusCell.h文件
TXStatusCell.m文件
TXStatusFrame.h文件
TXStatusFrame.m文件
控制器部分
TXViewController.h文件
TXViewController.m文件
3.实现效果
四、优化
在给自定义cell中重写set方法时,设置了微博的数据,还同时设置了frame,那么既然已经在frame模型中计算出了frame,这里就不需要再进行一次多余的计算了。修改代码,在cell里拿到weiboframe模型,就能拿到所有的frame。在自定义的cell里边,不再保存weibo而是保存weiboframe的属性。
说明:只对项目的三个文件进行了修改。
示意图:
一、需要改进的地方
还需改进的地方:cell的高度需要根据每条微博的数据进行动态设置。
设置cell的高度可以有两种方式,一种是通过rowheight属性来进行设置,一种是通过代理来进行设置。通过属性设置适用于每行的高度一致,使用代理适用于每行的高度不一致的情况。
二、实现思路
在这个应用中,每个cell的高度是根据内容来确定的,所以在这里我们通过代理来设置cell的高度。
获取到图片最大的Y值或者是文字最大的Y值,在cell中设置一个新的变量。
判断一下,如果有配图,则高度等于配图的高度+间隙的高度,如果没有配图那么高度等于文字的高度+间隙的高度。
在自定义cell的setting frame方法中计算出行高,而要在主控制器中进行使用,怎么办才能拿到数据?
计算行高的方法最终是由cellforrow(setweibo->settingframe->计算行高)调用的,如果要拿到行高的话,需要先调用cellforrow这个方法。
查看cellforrow和heughtforrow这两个方法是谁先调用,结果显示是heiforrow先调用。
拿不到计算的行高?怎么办?
让它在计算heightforrow之前就计算出行高。计算行高,依赖于其他控件中的位置,位置依赖于模型中的数据。
拿到模型数据,就可以计算出高度。
那么在哪里可以拿到数据模型呢?
在懒加载中创建模型,就可以拿到模型,计算所有控件的frame,在懒加载中就可以获得行高。
拿到模型后可以计算出5个frame,那么就使用一个模型,把着5个frame保存起来,将来一个自定义的cell就对应一个frame模型。
新建一个类,继承自nsobject,这个类专门用来保存每一行数据的frame。在类中创建5个对应的frame属性,(CGRECT)以及一个行高。添加一个模型数据,当别人给我一个模型数据的时候,我就可以通过重写set方法,设置模型数据的frame.
把之前的frame计算方法拷贝过去。(为什么?)
在懒加载方法中,根据模型数据创建frame模型,往数组里面添加的时候添加frame模型,此时该数组中既有所有的数据模型,又拥有对应的frame。
在代理方法中,获取到当前索引对应的frame。
三、实现代码
1.项目文件结构
2.代码
模型部分
TXStatus.h文件
// Created by 鑫 on 14-10-12. // Copyright (c) 2014年 梁镋鑫. All rights reserved. // #import <Foundation/Foundation.h> @interface TXStatus : 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
TXStatus.m文件
#import "TXStatus.h" #import "TXStatus.h" @implementation TXStatus - (instancetype)initWithDict:(NSDictionary *)dict { if (self = [super init]) { [self setValuesForKeysWithDictionary:dict]; } return self; } + (instancetype)statusWithDict:(NSDictionary *)dict { return [[self alloc] initWithDict:dict]; } @end
视图部分
TXStatusCell.h文件
#import <UIKit/UIKit.h> @class TXStatusFrame; @interface TXStatusCell : UITableViewCell @property (nonatomic, strong) TXStatusFrame *statusFrame; + (instancetype)cellWithTableView:(UITableView *)tableView; @end
TXStatusCell.m文件
// // 昵称的字体 #define TXNameFont [UIFont systemFontOfSize:14] // 正文的字体 #define TXTextFont [UIFont systemFontOfSize:15] #import "TXStatusCell.h" #import "TXStatus.h" #import "TXStatusFrame.h" @interface TXStatusCell() /** * 头像 */ @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 TXStatusCell /** * 构造方法(在初始化对象的时候会调用) * 一般在这个方法中添加需要显示的子控件 */ - (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.backgroundColor = [UIColor redColor]; nameView.font = TXNameFont; [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.backgroundColor = [UIColor blueColor]; textView.numberOfLines = 0; textView.font = TXTextFont; [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:(TXStatusFrame *)statusFrame { _statusFrame = statusFrame; // 1.设置数据 [self settingData]; // 2.设置frame [self settingFrame]; } /** * 设置数据 */ - (void)settingData { // 微博数据 TXStatus *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 */ /** * 设置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"; TXStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; if (cell == nil) { cell = [[TXStatusCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID]; } return cell; } - (void)awakeFromNib { // Initialization code } - (void)setSelected:(BOOL)selected animated:(BOOL)animated { [super setSelected:selected animated:animated]; // Configure the view for the selected state } @end
TXStatusFrame.h文件
// Created by 鑫 on 14-10-12. // Copyright (c) 2014年 梁镋鑫. All rights reserved. // #import <Foundation/Foundation.h> @class TXStatus; @interface TXStatusFrame : NSObject /** * 头像的frame */ @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) TXStatus *status; @end
TXStatusFrame.m文件
// Created by 鑫 on 14-10-12. // Copyright (c) 2014年 梁镋鑫. All rights reserved. // // 昵称的字体 #define TXNameFont [UIFont systemFontOfSize:14] // 正文的字体 #define TXTextFont [UIFont systemFontOfSize:15] #import "TXStatusFrame.h" #import "TXStatus.h" @implementation TXStatusFrame /** * 计算文字尺寸 * * @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:(TXStatus *)status { _status = status; // 子控件之间的间距 CGFloat padding = 10; // 1.头像 CGFloat iconX = padding; CGFloat iconY = padding; CGFloat iconW = 30; CGFloat iconH = 30; _iconF = CGRectMake(iconX, iconY, iconW, iconH); // 2.昵称 // 文字的字体 CGSize nameSize = [self sizeWithText:self.status.name font:TXNameFont 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:TXTextFont 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
控制器部分
TXViewController.h文件
#import <UIKit/UIKit.h> @interface TXViewController : UITableViewController @end
TXViewController.m文件
// Created by 鑫 on 14-10-12. // Copyright (c) 2014年 梁镋鑫. All rights reserved. // #import "TXViewController.h" #import "TXStatus.h" #import "TXStatusCell.h" #import "TXStatusFrame.h" @interface TXViewController () @property (nonatomic, strong) NSArray *statusFrames; @end @implementation TXViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. //行高 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.创建TXStatus模型对象 TXStatus *status = [TXStatus statusWithDict:dict]; // 3.2.创建TXStatusFrame模型对象 TXStatusFrame *statusFrame = [[TXStatusFrame alloc] init]; statusFrame.status = status; // 3.2.添加模型对象到数组中 [statusFrameArray addObject:statusFrame]; } // 4.赋值 _statusFrames = statusFrameArray; } return _statusFrames; } #pragma mark - 实现数据源方法 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.statusFrames.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // 1.创建cell TXStatusCell *cell = [TXStatusCell cellWithTableView:tableView]; // 2.在这个方法算好了cell的高度 cell.statusFrame = self.statusFrames[indexPath.row]; // 3.返回cell return cell; } #pragma mark - 实现代理方法 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { // 取出这行对应的frame模型 TXStatusFrame *statusFrame = self.statusFrames[indexPath.row]; return statusFrame.cellHeight;} - (BOOL)prefersStatusBarHidden { return YES; } @end
3.实现效果
四、优化
在给自定义cell中重写set方法时,设置了微博的数据,还同时设置了frame,那么既然已经在frame模型中计算出了frame,这里就不需要再进行一次多余的计算了。修改代码,在cell里拿到weiboframe模型,就能拿到所有的frame。在自定义的cell里边,不再保存weibo而是保存weiboframe的属性。
说明:只对项目的三个文件进行了修改。
示意图:
相关文章推荐
- iOS开发UI篇—以微博界面为例使用纯代码自定义cell程序编码全过程(三·完结)
- iOS开发UI篇—以微博界面为例使用纯代码自定义cell程序编码全过程(一)
- iOS开发UI篇—以微博界面为例使用纯代码自定义cell程序编码全过程(三·完结)
- iOS开发UI篇—以微博界面为例使用纯代码自定义cell程序编码全过程(一) - 文顶顶
- iOS开发UI篇—以微博界面为例使用纯代码自定义cell程序编码全过程(二)
- iOS开发UI篇—以微博界面为例使用纯代码自定义cell程序编码全过程(三·完结)
- iOS开发UI篇—以微博界面为例使用纯代码自定义cell程序编码全过程(一)
- iOS开发UI篇—以微博界面为例使用纯代码自定义cell程序编码全过程(二)
- iOS开发UI篇—以微博界面为例使用纯代码自定义cell程序编码全过程(二) - 文顶顶
- iOS开发UI篇—以微博界面为例使用纯代码自定义cell程序编码全过程(三·完结) - 文顶顶
- iOS开发UI篇—以微博界面为例使用纯代码自定义cell程序编码全过程
- iOS开发UI篇—以微博界面为例使用纯代码自定义cell程序编码全过程
- iOS开发UI篇—以微博界面为例使用纯代码自定义cell程序编码全过程(一)
- iOS开发UI篇—以微博界面为例使用纯代码自定义cell程序编码全过程(二)
- ios开发UI篇—使用纯代码自定义UItableviewcell实现一个简单的微博界面布局
- ios开发UI篇—使用纯代码自定义UItableviewcell实现一个简单的微博界面布局
- ios开发UI篇—使用纯代码自定义UItableviewcell实现一个简单的微博界面布局
- ios开发UI篇—使用纯代码自定义UItableviewcell实现一个简单的微博界面布局
- ios开发UI篇—使用纯代码自定义UItableviewcell实现一个简单的微博界面布局
- ios开发UI篇—使用纯代码自定义UItableviewcell实现一个简单的微博界面布局