不等高cell的搭建(一)

一.界面搭建

1.确定开发模式

如果界面是固定的,可以用xib

界面的一些内容不固定,就用纯代码

cell用什么方式去开发(我们采用纯代码和xib结合的方式)

2.划分层次结构

2.1 怎么划分?

按照功能划分

按照隐藏效果:在某些条件下,一些控件要一起隐藏,就可以放在同一模块中(前提是这些控件集中在一起)

2.2 分析界面发现cell的middleView和commentView不确定要不要显示

所以,cell采用纯代码方法搭建

3.自定义cell

3.1在创建cell的时候,就把所有可能显示的模块全部添加到cell上

把所有可能出现的模块(控件)全部添加到cell里面,然后根据需求再决定某些模块(控件)是显示还是隐藏

3.2根据服务器数据,决定某些模块是否隐藏

3.3在哪里创建cell?

采用注册的方法,底层会自动调用initWithStyle方法来创建cell

4.一个模块一个模块去搭建

4.1把cell分解为四个模块,如上图

4.2先把一个模块所有的内容(搭建界面)和业务逻辑处理完,在去处理下一个模块

4.3模块的处理方式:先搭建界面,再处理界面业务逻辑

4.4优点:业务逻辑清晰,不容易混淆

二.topView模块开发

1.xib搭建界面

1.1分析界面有哪些控件来搭建

1.2自定义uiview并创建xib,描述好界面后,把界面添加到cell里面

2.请求数据

2.1 查看接口文档,使用afn发送网络请求

2.2网络请求成功时,把数据转换成模型

2.3在模型中定义属性(先自定义模型)

查看界面需要使用哪些数据,就找到定义数据的属性定义到模型中

2.3自定义视图模型,视图模型包含模型(就是在视图模型中定义一个模型的属性)

2.4遍历模型,全部转换为视图模型

创建视图模型对象

用视图模型的模型属性来接收模型

把视图模型保存到数组中

3.在视图模型中计算cell子控件的frame和高度

3.1什么时候计算的

在模型转视图模型的时候计算的

3.2在哪里计算的?

重写视图模型的模型属性的set方法,在方法里面计算cell的frame和高度,并定义属性保存起来

因为,在模型转视图模型的时候,会把模型传给视图模型的模型属性,底层会触发视图模型的模型属性set方法,这个时候就去计算了

3.3 cell的高度计算

cell的高度就是Y轴方向最后一个控件的最大Y值

4.展示数据

4.1怎么展示?

在自定义cell里面定义视图模型属性

创建cell之后,从数组中取出对应的视图模型,给cell的视图模型属性赋值(触发视图模型的set方法)

4.2模型怎么接收数据的?

在cell视图模型属性的set方法里面,设置cell的frame和cell的高度(直接从视图模型中去)

在把视图模型的数据直接赋值给模型(触发模型的set方法)

重写模型的set方法,然后给界面的UI元素赋值,这样就能在界面上看到数据了

5.注意点

5.1 cell会循环利用,设置某项属性后,一定要记得还原

5.2 运行会报一些莫名其妙的约束冲突

是系统的自动拉伸约束有冲突,取消掉就可以了

三.middleView模块搭建

middleView模块的样式也分很多种

我们可以利用xib搭建不同样式的middleView,然后根据服务器数据决定显示哪种样式的middleView

注意:一定要把其它样式的middleView隐藏,还需要在其它地方还原,防止循环引用

根据需求我们可以把middleView分为四种样式:

1.textView样式

也就是没有middleView,这种样式只要不显示middleView就可以了(把pictureView,videoView,voiceView隐藏)

也不需要计算frame的高度了

2.pictureView样式

2.1 分析界面有哪些控件组成, 界面怎么搭建?

加载图片的时候:有一个gif图标,用ImageView来搭建,进度条可以放在一个view里面

文字部分:如果是图片用ImageView,如果是文字,用label或button都行, 需要与用户交互就用button

显示图片时:图片用ImageView搭建,下面的查看大图用button(有图片和文字,还有背景图片,还要与用户交互,只能用button)

由于界面是固定的,可以采用xib来搭建

2.2 把pictureView添加到cel里面

2.3 请求数据

2.4 在视图模型中计算cell子控件的frame和高度

2.4.1首先判断数据是什么类型的

返回的类型是NSInther,可读性太差,可以定义枚举来替代,可读性就很好

1 typedef enum : NSUInteger {
2     XTThemeItemTypeAll = 1,
3     XTThemeItemTypeVideo = 41,
4     XTThemeItemTypeVoice = 31,
5     XTThemeItemTypePicture = 10,
6     XTThemeItemTypeText = 29
7 } XTThemeItemType;

注意:定义枚举的快捷键是:enum

2.4.2 如果是text类型的就不需要计算了

2.4.3 如果图片实际高度太高,我们就在模型里面定义一个属性来记录是否是大图

2.4.4 给大图设置一个固定高度,不需要把大图全部展示出来了

 1      // middleView:一样计算方式
 2     // 不是段子的时候,才需要计算中间View的Frame
 3     if (item.type != XMGThemeItemTypeText) {
 4         CGFloat middleW = textW;
 5         CGFloat middleH = middleW / item.width * item.height;
 6         if (middleH > XTScreenH) {  // 大图
 7             middleH = 300;
 8             item.is_bigPicture = YES;
 9         }
10         CGFloat middleX = margin;
11         CGFloat middleY = _cellH;
12         _middleViewFrame = CGRectMake(middleX, middleY, middleW, middleH);
13         _cellH = CGRectGetMaxY(_middleViewFrame) + margin;
14     }

2.5 运行发现,如果是大图,图片就被压缩了,很难看,怎么解决?

ImageView默认是图片填充的,就是把图片拉伸或压缩成整个ImageView的大小

设置ImageView的内容模式,不让它压缩 UIViewContentModeTop

2.6 设置内容模式,发现虽然图片不被压缩,但是图片不能填充ImageView(两边是空的) 怎么解决?

UIViewContentModeTop默认是图片上面显示到ImageView的顶部,但是不会进行拉伸或压缩

我们需要先对图片进行拉伸或压缩处理,然后再设置 UIViewContentModeTop 就可以了

2.7 怎么对图片进行拉伸或压缩处理?

可以用绘图,生成一张新的拉伸或压缩好的图片

2.8 怎么绘图?

2.8.1 开启图形上下文

2.8.2 绘制图片

2.8.3 获取新的图片

2.8.4 关闭图形上下文

2.9 对图片处理进行性能优化

2.9.1 每次设置图片,都要进行绘图,有可能重复绘图,性能不好,怎么优化?

把处理好的图片缓存到磁盘(沙盒)里面,下次再设置这张图片时,直接从磁盘取

2.9.2 怎么对图片缓存处理?

自己写方法太麻烦, SDImageCache.h内部有方法缓存图片,直接调用它的方法来进行缓存

1   [[SDImageCache sharedImageCache] storeImage:image forKey:item.image0];
2           注意:要到入头文件: #import <SDImageCache.h>

2.9.3 怎么从磁盘中去图片?

同样也是调用SDImageCache.h方法来取

        UIImage *image = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:item.image0];

注意:key值就是图片的url

2.10 刚开始加载图片时,进度条怎么设置?

2.10.1 需要设置一个功能模块的时候,我们要先去找有没有做该功能模块的框架,有就直接拿来用

2.10.2 没有的话,就找一个功能差不多的模块来修改一下

2.10.3 怎么去查找一个框架?

 1            - (void)awakeFromNib
 2 {
 3     _progressView.progressLabel.textColor = [UIColor whiteColor];
 4     _progressView.progressTintColor = [UIColor whiteColor];
 5     _progressView.roundedCorners = 10;
 6
 7     _progressView.progressLabel.text = [NSString stringWithFormat:@"%.1f%%",0.0 * 100];
 8     _progressView.progress = 0;
 9 }
10
11 - (void)setItem:(XMGThemeItem *)item
12 {
13     _item = item;
14
15     // 设置图片
16     UIImage *image = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:item.image0];
17     if (image) {   如果有图片直接设置,并把进度设为100%
18         _imageView.image = image;
19         _progressView.progressLabel.text = [NSString stringWithFormat:@"%.1f%%",1.0 * 100];
20         _progressView.progress = 1;
21     } else {    如果没有图片,就先把进度设置为0 ,再去下载图片
22         _progressView.progressLabel.text = [NSString stringWithFormat:@"%.1f%%",0.0 * 100];
23         _progressView.progress = 0;
24         // 下载网络图片
25         [_imageView sd_setImageWithURL:[NSURL URLWithString:item.image0]  placeholderImage:nil options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize) {
26             进度就为已下载的文件大小 / 总文件大小
27             CGFloat progress = 1.0 * receivedSize / expectedSize;
28             运行发现,进度有时候为-0,打印发现总文件大小该开始为-0       当为-0 的时候就返回
29           注意:该block会频换调用,所以  returen一次没关系
30             if (expectedSize < 0) return ;
31             _progressView.progressLabel.text = [NSString stringWithFormat:@"%.1f%%",progress * 100];
32             _progressView.progress = progress;
33
34         } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
35
36             if (!item.is_bigPicture) return ;
37
38             // 生成一个新拉伸好图片
39             CGFloat w = XMGScreenW - 20;
40             CGFloat h = w / item.width * item.height;
41
42             // 开启图形上下文
43             UIGraphicsBeginImageContextWithOptions(CGSizeMake(w, h), NO, 0);
44             // 绘图
45             [image drawInRect:CGRectMake(0, 0, w, h)];
46             // 获取上下文图片
47             image = UIGraphicsGetImageFromCurrentImageContext();
48             // 保存图片到沙盒
49             [[SDImageCache sharedImageCache] storeImage:image forKey:item.image0];
50             // 关闭上下文
51             UIGraphicsEndImageContext();
52
53             _imageView.image = image;
54         }];
55     }
56     根据服务器数据,决定gif图片是否显示
57     _gifView.hidden = !item.is_gif;
58      根据自己判断保存的属性,来决定显示大图按钮是否显示
59     _seeBigButton.hidden = !item.is_bigPicture;
60
61     if (item.is_bigPicture) {
62         _imageView.contentMode = UIViewContentModeTop;
63         _imageView.clipsToBounds = YES;
64     } else {
65         _imageView.contentMode = UIViewContentModeScaleToFill;
66         _imageView.clipsToBounds = NO;
67     }
68 }

3.videoView样式  和  voiceView样式

3.1 由于这两个模块基本相同,处理方法也差不多

注意:把搭建好的xib的view拷贝到另一个xib里面的时候,会把对应的连线也拷过去,一定要先删除这些连线,再继续使用

3.2 根据类型,只需要设置中间按钮的图片就可以了

3.3 xib搭建界面,并把界面添加到cell里面

3.4 请求数据

3.5 在视图模型中计算cell子控件的frame和高度

3.6 展示数据

3.6.1 在videoView或voiceView的模型里设置数据的时候,要对数据进行处理

3.6.2 为什么要处理?

服务器返回的时间数据是以秒为单位的,需求以  00:00  来显示

3.6.3 怎么处理?

1     NSInteger minute = item.voicetime / 60;
2     NSInteger second = item.voicetime % 60;
3     self.timeLabel.text = [NSString stringWithFormat:@"%02ld:%02ld",minute,second];

4 在cell模型属性的set方法里面统一设置middleView各个模块的frame的是否隐藏

 1     // middleView
 2     if (vm.item.type == XMGThemeItemTypePicture) { // 图片
 3         _pictureView.hidden = NO;
 4         _videoView.hidden = YES;
 5         _voiceView.hidden = YES;
 6
 7         _pictureView.item = vm.item;
 8         _pictureView.frame = vm.middleViewFrame;
 9
10     } else if (vm.item.type == XMGThemeItemTypeVideo) { // 视频
11         _pictureView.hidden = YES;
12         _videoView.hidden = NO;
13         _voiceView.hidden = YES;
14
15         _videoView.item = vm.item;
16         _videoView.frame = vm.middleViewFrame;
17     } else if (vm.item.type == XMGThemeItemTypeVoice) { // 音频
18         _pictureView.hidden = YES;
19         _videoView.hidden = YES;
20         _voiceView.hidden = NO;
21
22         _voiceView.item = vm.item;
23         _voiceView.frame = vm.middleViewFrame;
24
25     } else {
26         _voiceView.hidden = YES;
27         _pictureView.hidden = YES;
28         _videoView.hidden = YES;
29     }
时间: 2024-10-19 11:00:09

不等高cell的搭建(一)的相关文章

不等高cell的tableView界面搭建

一.搭建界面 1.界面分析 分析界面的层次结构,分析界面应该用什么控件来搭建 2.界面层次结构 分析之后,我们可以把这个界面分为四个模块(topView middleView commentView bottomView) 这种复杂的界面,我们一般称为:不等高cell 3.界面搭建方式 分析发现,界面大部分是不能确定的(文字高度,有没有图片,评论) 所以我们采用纯代码的方法来搭建界面 但是复杂的界面我们划分过之后,有些小模块里面的内容是固定的 这些固定的小模块我们可以采用xib来搭建 4.有些模

自定义不等高cell—storyBoard或xib自定义不等高cell

1.iOS8之后利用storyBoard或者xib自定义不等高cell: 对比自定义等高cell,需要几个额外的步骤(iOS8开始才支持) 添加子控件和contentView(cell的contentView)之间的间距约束(需要代码控制约束) 设置tableViewCell的真实行高和估算行高 // 以下两行代码就被苹果成为self0sizing技术,可惜只能在iOS8及其之后应用 // 告诉tableView所有cell的真实高度是自动计算(根据设置的约束来计算) self.tableVie

不等高cell搭建(二)

一.commentView模块搭建 commentView样式分为两种 1.xib搭建界面 1.1 因为评论的样式大体上一样,我们可以用同一个xib来处理 1.2 最热评论   用一个label来搭建 1.3 下面的内容不一样 1.3.1 文本样式的评论,下面也用一个label搭建就可以了 label约束设置为左右和上面固定间距,这样,高度会随着内容缩放,前提是设置label为0行 1.3.2 声音样式评论 声音样式的评论.高度是固定的 先添加一个view在文本评论的位置(根据数据再决定到时候哪

纯代码自定义不等高cell

数据模型.plist解析这里就不过多赘述. 错误思路之一: 通过在heightForRowAtIndexPath:方法中调用cellForRowAtIndexPath:拿到cell,再拿到cell的子控件的最大Y值的方法是不可取的.会出现死循环,因为cellForRowAtIndexPath:方法中会调用heightForRowAtIndexPath:方法.错误思路之二: 在layoutSubviews方法中,根据子控件的高度,计算cell的高度.先初始化一个变量为0为cell的高度,计算出来所

处理不等高TableViewCell

课题一:如何计算Cell高度 方案一:直接法(面向对象) 想知道妹纸爱你有多深?直接去问妹纸本人吧! 嗯!Cell也是一样的,想知道cell到底有多高?直接问Cell本人就好了.直接法,就是把数据布局到Cell上,然后拿到Cell最底部控件的MaxY值. 第一步:创建Cell并正确设置约束,使文字区域高度能够根据文字内容多少自动调整 第一步 - 添加好约束.gif 第二步:再给这个Cell添加点别的东东,就叫这个东东BottomCub了.为Cub添加好约束. 第二步 - 随便添加点什么.gif

iOSTableViewCell不等高的几种方法

方案一:直接法(面向对象) 直接法,就是把数据布局到Cell上,然后拿到Cell最底部控件的MaxY值. 第一步:创建Cell并正确设置约束,使文字区域高度能够根据文字内容多少自动调整 添加好约束 第二步:再给这个Cell添加点别的东东,就叫这个东东BottomCub了.为Cub添加好约束. 随便添加点什么 第三步:为这个Cell写一个返回Cell高度 - 也就是BottomCub最大Y值的方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

iOS之处理不等高TableViewCell的几种方法

课题一:如何计算Cell高度 方案一:直接法(面向对象) 直接法,就是把数据布局到Cell上,然后拿到Cell最底部控件的MaxY值. 第一步:创建Cell并正确设置约束,使文字区域高度能够根据文字内容多少自动调整 添加好约束 第二步:再给这个Cell添加点别的东东,就叫这个东东BottomCub了.为Cub添加好约束. 随便添加点什么 第三步:为这个Cell写一个返回Cell高度 - 也就是BottomCub最大Y值的方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

iOS-UI控件之UITableView(三)- 自定义不等高的cell

Storyboard_不等高 对比自定义等高cell,需要几个额外的步骤(iOS8开始才支持) 添加子控件和contentView之间的间距约束 设置tableViewCell的真实行高和估算行高 // 告诉tableView所有cell的真实高度是自动计算(根据设置的约束来计算) self.tableView.rowHeight = UITableViewAutomaticDimension; // 告诉tableView所有cell的估算高度 self.tableView.estimated

iOS-UI控件之UITableView(二)- 自定义不等高的cell

不等高的cell 给模型增加frame数据 所有子控件的frame cell的高度 @interface XMGStatus : NSObject /**** 文字\图片数据 ****/ // ..... /**** frame数据 ****/ /** 头像的frame */ @property (nonatomic, assign) CGRect iconFrame; // ..... /** cell的高度 */ @property (nonatomic, assign) CGFloat c