小说哥

导航

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 *)dict
13 {
14     return [[self alloc] initWithDict:dict];
15 }
16 
17 @end

 

视图部分
TXStatusCell.h文件
1 #import <UIKit/UIKit.h>
2 @class TXStatusFrame;
3 @interface TXStatusCell : UITableViewCell
4 @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)maxSize
134 {
135     NSDictionary *attrs = @{NSFontAttributeName : font};
136     return [text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;
137 }
138 
139 /**
140  *  设置frame
141  */
142 /**
143  *  设置frame
144  */
145 - (void)settingFrame
146 {
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 *)tableView
165 {
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)awakeFromNib
177 {
178     // Initialization code
179 }
180 
181 - (void)setSelected:(BOOL)selected animated:(BOOL)animated
182 {
183     [super setSelected:selected animated:animated];
184 
185     // Configure the view for the selected state
186 }
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  *  头像的frame
10  */
11 @property (nonatomic, assign, readonly) CGRect iconF;
12 /**
13  *  昵称的frame
14  */
15 @property (nonatomic, assign, readonly) CGRect nameF;
16 /**
17  *  会员图标的frame
18  */
19 @property (nonatomic, assign, readonly) CGRect vipF;
20 /**
21  *  正文的frame
22  */
23 @property (nonatomic, assign, readonly) CGRect textF;
24 /**
25  *  配图的frame
26  */
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 TXStatusFrame
12 /**
13  *  计算文字尺寸
14  *
15  *  @param text    需要计算尺寸的文字
16  *  @param font    文字的字体
17  *  @param maxSize 文字的最大尺寸
18  */
19 - (CGSize)sizeWithText:(NSString *)text font:(UIFont *)font maxSize:(CGSize)maxSize
20 {
21     NSDictionary *attrs = @{NSFontAttributeName : font};
22     return [text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;
23 }
24 -(void)setStatus:(TXStatus *)status
25 { _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 : UITableViewController
4 
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 @end
13 
14 @implementation TXViewController
15 - (void)viewDidLoad
16 {
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 *)statusFrames
24 {
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)section
54 {
55     return self.statusFrames.count;
56 }
57 
58 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
59 {
60     // 1.创建cell
61     TXStatusCell *cell = [TXStatusCell cellWithTableView:tableView];
62     
63     // 2.在这个方法算好了cell的高度
64     cell.statusFrame = self.statusFrames[indexPath.row];
65     
66     // 3.返回cell
67     return cell;
68 }
69 #pragma mark - 实现代理方法
70 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
71 {
72     
73     // 取出这行对应的frame模型
74     TXStatusFrame *statusFrame = self.statusFrames[indexPath.row];
75     return statusFrame.cellHeight;}
76 
77 
78 - (BOOL)prefersStatusBarHidden
79 {
80     return YES;
81 }
82 
83 
84 
85 @end

 

3.实现效果

       

四、优化

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

 

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

 示意图:

posted on 2014-11-02 15:40  小说哥  阅读(303)  评论(0编辑  收藏  举报