首页 > 代码库 > iOS开发UI篇—以微博界面为例使用纯代码自定义cell程序编码全过程(二)

iOS开发UI篇—以微博界面为例使用纯代码自定义cell程序编码全过程(二)

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文件
 1 //  Created by 鑫 on 14-10-12. 2 //  Copyright (c) 2014年 梁镋鑫. All rights reserved. 3 // 4  5 #import <Foundation/Foundation.h> 6  7 @interface TXStatus : NSObject 8 @property (nonatomic, copy) NSString *text; // 内容 9 @property (nonatomic, copy) NSString *icon; // 头像10 @property (nonatomic, copy) NSString *name; // 昵称11 @property (nonatomic, copy) NSString *picture; // 配图12 @property (nonatomic, assign) BOOL vip;13 14 - (instancetype)initWithDict:(NSDictionary *)dict;15 + (instancetype)statusWithDict:(NSDictionary *)dict;16 17 @end

 

TXStatus.m文件
 1 #import "TXStatus.h" 2 #import "TXStatus.h" 3 @implementation TXStatus 4 - (instancetype)initWithDict:(NSDictionary *)dict 5 { 6     if (self = [super init]) { 7         [self setValuesForKeysWithDictionary:dict]; 8     } 9     return self;10 }11 12 + (instancetype)statusWithDict:(NSDictionary *)dict13 {14     return [[self alloc] initWithDict:dict];15 }16 17 @end

 

视图部分
TXStatusCell.h文件
1 #import <UIKit/UIKit.h>2 @class TXStatusFrame;3 @interface TXStatusCell : UITableViewCell4 @property (nonatomic, strong) TXStatusFrame *statusFrame;5 + (instancetype)cellWithTableView:(UITableView *)tableView;6 @end

 

TXStatusCell.m文件
  1 //  2 // 昵称的字体  3 #define TXNameFont [UIFont systemFontOfSize:14]  4 // 正文的字体  5 #define TXTextFont [UIFont systemFontOfSize:15]  6 #import "TXStatusCell.h"  7 #import "TXStatus.h"  8 #import "TXStatusFrame.h"  9 @interface TXStatusCell() 10  11 /** 12  *  头像 13  */ 14 @property (nonatomic, weak) UIImageView *iconView; 15 /** 16  *  昵称 17  */ 18 @property (nonatomic, weak) UILabel *nameView; 19 /** 20  *  会员图标 21  */ 22 @property (nonatomic, weak) UIImageView *vipView; 23 /** 24  *  正文 25  */ 26 @property (nonatomic, weak) UILabel *textView; 27 /** 28  *  配图 29  */ 30 @property (nonatomic, weak) UIImageView *pictureView; 31  32  33 @end 34 @implementation TXStatusCell 35 /** 36  *  构造方法(在初始化对象的时候会调用) 37  *  一般在这个方法中添加需要显示的子控件 38  */ 39 - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier 40 { 41     self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 42     if (self) { 43         // 1.头像 44         UIImageView *iconView = [[UIImageView alloc] init]; 45         [self.contentView addSubview:iconView]; 46         self.iconView = iconView; 47          48         // 2.昵称 49         UILabel *nameView = [[UILabel alloc] init]; 50         //        nameView.backgroundColor = [UIColor redColor]; 51         nameView.font = TXNameFont; 52         [self.contentView addSubview:nameView]; 53         self.nameView = nameView; 54          55         // 3.会员图标 56         UIImageView *vipView = [[UIImageView alloc] init]; 57         vipView.image = [UIImage imageNamed:@"vip"]; 58         [self.contentView addSubview:vipView]; 59         self.vipView = vipView; 60          61         // 4.正文 62         UILabel *textView = [[UILabel alloc] init]; 63         //        textView.backgroundColor = [UIColor blueColor]; 64         textView.numberOfLines = 0; 65         textView.font = TXTextFont; 66         [self.contentView addSubview:textView]; 67         self.textView = textView; 68          69         // 5.配图 70         UIImageView *pictureView = [[UIImageView alloc] init]; 71         [self.contentView addSubview:pictureView]; 72         self.pictureView = pictureView; 73     } 74     return self; 75 } 76 /** 77  *  在这个方法中设置子控件的frame和显示数据 78  */ 79 - (void)setStatusFrame:(TXStatusFrame *)statusFrame 80 { 81     _statusFrame = statusFrame; 82      83     // 1.设置数据 84     [self settingData]; 85      86     // 2.设置frame 87     [self settingFrame]; 88 } 89 /** 90  *  设置数据 91  */ 92 - (void)settingData 93 { 94     // 微博数据 95     TXStatus *status = self.statusFrame.status; 96      97     // 1.头像 98     self.iconView.image = [UIImage imageNamed:status.icon]; 99     100     // 2.昵称101     self.nameView.text = status.name;102     103     // 3.会员图标104     if (status.vip) {105         self.vipView.hidden = NO;106         107         self.nameView.textColor = [UIColor redColor];108     } else {109         self.vipView.hidden = YES;110         111         self.nameView.textColor = [UIColor blackColor];112     }113     114     // 4.正文115     self.textView.text = status.text;116     117     // 5.配图118     if (status.picture) { // 有配图119         self.pictureView.hidden = NO;120         self.pictureView.image = [UIImage imageNamed:status.picture];121     } else { // 没有配图122         self.pictureView.hidden = YES;123     }124 }125 126 /**127  *  计算文字尺寸128  *129  *  @param text    需要计算尺寸的文字130  *  @param font    文字的字体131  *  @param maxSize 文字的最大尺寸132  */133 - (CGSize)sizeWithText:(NSString *)text font:(UIFont *)font maxSize:(CGSize)maxSize134 {135     NSDictionary *attrs = @{NSFontAttributeName : font};136     return [text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;137 }138 139 /**140  *  设置frame141  */142 /**143  *  设置frame144  */145 - (void)settingFrame146 {147     // 1.头像148     self.iconView.frame = self.statusFrame.iconF;149     150     // 2.昵称151     self.nameView.frame = self.statusFrame.nameF;152     153     // 3.会员图标154     self.vipView.frame = self.statusFrame.vipF;155     156     // 4.正文157     self.textView.frame = self.statusFrame.textF;158     159     // 5.配图160     if (self.statusFrame.status.picture) {// 有配图161         self.pictureView.frame = self.statusFrame.pictureF;162     }163 }164 + (instancetype)cellWithTableView:(UITableView *)tableView165 {166     167     static NSString *ID = @"status";168     TXStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];169     if (cell == nil) {170         cell = [[TXStatusCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];171     }172     return cell;173 174 }175 176 - (void)awakeFromNib177 {178     // Initialization code179 }180 181 - (void)setSelected:(BOOL)selected animated:(BOOL)animated182 {183     [super setSelected:selected animated:animated];184 185     // Configure the view for the selected state186 }187 188 @end

 

TXStatusFrame.h文件
 1 //  Created by 鑫 on 14-10-12. 2 //  Copyright (c) 2014年 梁镋鑫. All rights reserved. 3 // 4  5 #import <Foundation/Foundation.h> 6 @class TXStatus; 7 @interface TXStatusFrame : NSObject 8 /** 9  *  头像的frame10  */11 @property (nonatomic, assign, readonly) CGRect iconF;12 /**13  *  昵称的frame14  */15 @property (nonatomic, assign, readonly) CGRect nameF;16 /**17  *  会员图标的frame18  */19 @property (nonatomic, assign, readonly) CGRect vipF;20 /**21  *  正文的frame22  */23 @property (nonatomic, assign, readonly) CGRect textF;24 /**25  *  配图的frame26  */27 @property (nonatomic, assign, readonly) CGRect pictureF;28 29 /**30  *  cell的高度31  */32 @property (nonatomic, assign, readonly) CGFloat cellHeight;33 @property (nonatomic, strong) TXStatus *status;34 @end

 

TXStatusFrame.m文件
 1 //  Created by 鑫 on 14-10-12. 2 //  Copyright (c) 2014年 梁镋鑫. All rights reserved. 3 // 4 // 昵称的字体 5 #define TXNameFont [UIFont systemFontOfSize:14] 6 // 正文的字体 7 #define TXTextFont [UIFont systemFontOfSize:15] 8  9 #import "TXStatusFrame.h"10 #import "TXStatus.h"11 @implementation TXStatusFrame12 /**13  *  计算文字尺寸14  *15  *  @param text    需要计算尺寸的文字16  *  @param font    文字的字体17  *  @param maxSize 文字的最大尺寸18  */19 - (CGSize)sizeWithText:(NSString *)text font:(UIFont *)font maxSize:(CGSize)maxSize20 {21     NSDictionary *attrs = @{NSFontAttributeName : font};22     return [text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;23 }24 -(void)setStatus:(TXStatus *)status25 { _status = status;26     27     // 子控件之间的间距28     CGFloat padding = 10;29     30     // 1.头像31     CGFloat iconX = padding;32     CGFloat iconY = padding;33     CGFloat iconW = 30;34     CGFloat iconH = 30;35     _iconF = CGRectMake(iconX, iconY, iconW, iconH);36     37     // 2.昵称38     // 文字的字体39     CGSize nameSize = [self sizeWithText:self.status.name font:TXNameFont maxSize:CGSizeMake(MAXFLOAT, MAXFLOAT)];40     CGFloat nameX = CGRectGetMaxX(_iconF) + padding;41     CGFloat nameY = iconY + (iconH - nameSize.height) * 0.5;42     _nameF = CGRectMake(nameX, nameY, nameSize.width, nameSize.height);43     44     // 3.会员图标45     CGFloat vipX = CGRectGetMaxX(_nameF) + padding;46     CGFloat vipY = nameY;47     CGFloat vipW = 14;48     CGFloat vipH = 14;49     _vipF = CGRectMake(vipX, vipY, vipW, vipH);50     51     // 4.正文52     CGFloat textX = iconX;53     CGFloat textY = CGRectGetMaxY(_iconF) + padding;54     CGSize textSize = [self sizeWithText:self.status.text font:TXTextFont maxSize:CGSizeMake(300, MAXFLOAT)];55     _textF = CGRectMake(textX, textY, textSize.width, textSize.height);56     57     // 5.配图58     if (self.status.picture) {// 有配图59         CGFloat pictureX = textX;60         CGFloat pictureY = CGRectGetMaxY(_textF) + padding;61         CGFloat pictureW = 100;62         CGFloat pictureH = 100;63         _pictureF = CGRectMake(pictureX, pictureY, pictureW, pictureH);64         65         _cellHeight = CGRectGetMaxY(_pictureF) + padding;66     } else {67         _cellHeight = CGRectGetMaxY(_textF) + padding;68     }69 70     71 }72 @end

 

控制器部分
TXViewController.h文件
1 #import <UIKit/UIKit.h>2 3 @interface TXViewController : UITableViewController4 5 @end

 

TXViewController.m文件
 1 //  Created by 鑫 on 14-10-12. 2 //  Copyright (c) 2014年 梁镋鑫. All rights reserved. 3 // 4  5 #import "TXViewController.h" 6 #import "TXStatus.h" 7 #import "TXStatusCell.h" 8 #import "TXStatusFrame.h" 9 @interface TXViewController ()10 @property (nonatomic, strong) NSArray *statusFrames;11 12 @end13 14 @implementation TXViewController15 - (void)viewDidLoad16 {17     [super viewDidLoad];18     // Do any additional setup after loading the view, typically from a nib.19     //行高20     self.tableView.rowHeight = 400;21 }22 23 - (NSArray *)statusFrames24 {25     if (_statusFrames == nil) {26         // 初始化27         // 1.获得plist的全路径28         NSString *path = [[NSBundle mainBundle] pathForResource:@"statuses.plist" ofType:nil];29         30         // 2.加载数组31         NSArray *dictArray = [NSArray arrayWithContentsOfFile:path];32         33         // 3.将dictArray里面的所有字典转成模型对象,放到新的数组中34         NSMutableArray *statusFrameArray = [NSMutableArray array];35         for (NSDictionary *dict in dictArray) {36             // 3.1.创建TXStatus模型对象37             TXStatus *status = [TXStatus statusWithDict:dict];38             39             // 3.2.创建TXStatusFrame模型对象40             TXStatusFrame *statusFrame = [[TXStatusFrame alloc] init];41             statusFrame.status = status;42             43             // 3.2.添加模型对象到数组中44             [statusFrameArray addObject:statusFrame];45         }46         47         // 4.赋值48         _statusFrames = statusFrameArray;49     }50     return _statusFrames;51 }52 #pragma mark - 实现数据源方法53 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section54 {55     return self.statusFrames.count;56 }57 58 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath59 {60     // 1.创建cell61     TXStatusCell *cell = [TXStatusCell cellWithTableView:tableView];62     63     // 2.在这个方法算好了cell的高度64     cell.statusFrame = self.statusFrames[indexPath.row];65     66     // 3.返回cell67     return cell;68 }69 #pragma mark - 实现代理方法70 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath71 {72     73     // 取出这行对应的frame模型74     TXStatusFrame *statusFrame = self.statusFrames[indexPath.row];75     return statusFrame.cellHeight;}76 77 78 - (BOOL)prefersStatusBarHidden79 {80     return YES;81 }82 83 84 85 @end

 

3.实现效果

       

四、优化

在给自定义cell中重写set方法时,设置了微博的数据,还同时设置了frame,那么既然已经在frame模型中计算出了frame,这里就不需要再进行一次多余的计算了。修改代码,在cell里拿到weiboframe模型,就能拿到所有的frame。在自定义的cell里边,不再保存weibo而是保存weiboframe的属性。

 

说明:只对项目的三个文件进行了修改。

 示意图:

iOS开发UI篇—以微博界面为例使用纯代码自定义cell程序编码全过程(二)