A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 Simpon 于 2016-10-24 09:53 编辑

原文出处:http://www.jianshu.com/p/968ca89014e3写在前面的话   楼主写一个UICollectionView,其中视图采用的是瀑布式布局,设为一列,高度由内容决定。相信大家遇见这个问题的时候,已经对于UICollectionViewCell有一定的了解,所以对于UICollectionViewLayout 布局问题就不过多阐述,
   对于UICollectionView的基本用法也不过多阐述。主要只针对cell的复用问题,用一定通俗的语言给大家进行分析(小子能力有限,若是其中有描述不正确的地方, 请大家指出)。那么本问主要是针对UICollectionViewController 中的 方法:
[Objective-C] 纯文本查看 复制代码
- (UICollectionViewCell*) collectionView: (UICollectionView*) collectionView cellForItemAtIndexPath:(NSIndexPath*) indexPath ;

以及自定义的BDCell这个继承与UICollectionViewCell 的类中:
[Objective-C] 纯文本查看 复制代码
@interface BDCell :UICollectionViewCell   

这两个部分进行,小子尽量用简单通俗的语句进行描述分析。
视图重叠显示

第一页正常


后面开始重叠显示

     白色为添加的 cell.backgroundView 这个不在重点讨论,但是这里还是有必要说一下 cell.backgroundViewcell. contentView  .
    我们观察下cell.backgroundView 和 cell.contentView 的层级关系.


layer

cell.backgroundView 即为离cell的viw 最近的一层  ,再其上添加的内容都将显示在这层之上.
cell的ContentView    即是添加在cell.backgroundView 之上的一层 ( 如果不添加即为透明层,         cell.backgroundVeiw 被阻挡不可交互)。
其中黄色部分是一个UIButton,固定添加在每个cell.contentView 的底部,简单代码:
在自定义的BDCell 中添加
[Objective-C] 纯文本查看 复制代码
-(void)addButton { }
float h =20;                                            //尺寸定义          
float w =self.backgroundView.bounds.size.width;
CGRect rect =CGRectMake(0,self.bounds.size.height-h, w, h);  
UIButton *btn = [ [ UIButtonalloc ] initWithFrame:rect ];
btn.backgroundColor = [ UIColoryellowColor ];
btn.tag=100;                                          //添加标记,后说
[self.contentView addSubview:  btn  ];  //加到contentView 
}

而在UICollectionViewController 中 ,代码如下
在UICollectionViewController   viewDidLoad 中注册
[Objective-C] 纯文本查看 复制代码
[ self.collectionView    registerClass:[BDCellclass]   forCellWithReuseIdentifier:reuseIdentifier  ];
- (UICollectionViewCell*) collectionView:(UICollectionView*)collectionView  cellForItemAtIndexPath:(NSIndexPath*)  indexPath    {
 BDCell *cell =     [collectionView    dequeueReusableCellWithReuseIdentifier:    reuseIdentifier    forIndexPath:indexPath];
  return  cell;
}

以上都是最基本的写法,没有过多的描述cell ,也比较粗陋。
寻找问题     好了,这里终于说到重用机制了,首先如果你是apple,你不希望一个应用里面有太多cell对象,影响内存,如果上百个cell,如果按view的方式,那么就有上百个实例对象。 apple肯定是不希望这么做的,不符合设计思想,如果是你,你会怎么做? 这个问题对于有些数量比较多的cell是必须解决的。
    那么我如果是apple,我会想, 对于设备而言,物理尺寸是限制了的,首先我必须创建屏幕尺寸所容纳的个数的cell ,这点没办法改变 。  但是在下滑的时候,将要展示更多cell的时候,我事先不会全部加载出来,对于内存压力太大, 那么,我就预先展示一个就可以了,作为响应的缓冲。
在collectionView 第一屏cell ,是这样的。


最初的状态


当我们滑动的时候,就需要做一些小手段,即不增加内存压力,也让用户看起来不会迟钝。预先展示一个即可。 通过每个cell的ID , 从复用吃中寻找有ID的cell, 拿到下面来用即可。 虽然在cell外观上,看起来是没有区别,但是数据上是刷新了的。 这样就会造成视图重叠的效果。

滑动

那么,我们来检验下,真是只创建了有限的cell。 在cell初始化中,我们打印下。



     在我滑动到后面很多行的时候,cell的初始化方式始终只是创建了有限的几个,也就是说,在我滑动的过程中,没有创建多个cell。  我在屏幕上所看见的cell,还是最初的那几个cell,只不过来回的逗我玩呢。
     但是,cell的view还是原来的,也不是完全的拿以前的cell添加到下面,而是进行了一定的改变,这种改变来自与数据。 上面有提过,数据导入不同,cell 的view复用, 这样就解决了 内存压力的问题,但是这个问题所遗留下来的局限性也是有的,我们自定义的cell,是动态的大小,你后面虽然复用了我前面的cell,但是在尺寸问题上,我的UIButton.添加的位置也应该是不同。
    那么,我们这里就需要针对这个毛病,做一些手段了,在不破坏apple设计思想上,不增大内存压力之上,需要把以前cell的子视图重新排列一下。  
寻找问题解决方法
    怎样重排呢? 虽然我cell的的初始化方法只调用了一次,但是我可以在以下方法中调用我cell的一个公开接口,对其内部的东西进行一些手术。
[Objective-C] 纯文本查看 复制代码
- (UICollectionViewCell*) collectionView:(UICollectionView*)collectionView  cellForItemAtIndexPath:(NSIndexPath*)  indexPath    {
BDCell *cell =     [collectionView    dequeueReusableCellWithReuseIdentifier:    reuseIdentifier    forIndexPath:indexPath];

[cell     cherkR  ];   //检查是否来自复用池 
return  cell;
}

     这样是可行的,那么我们回到我们的自定义cell,内部的问题内部解决。 先不说代码,先说说内部解决的思路?
    怎样检查是不是来自复用的? 这个问题我知道肯定有,但是我这就不去添加过多的代码,换个想法,我检查复用的原因就是想对内部进行一个重排列, 那我牺牲一定的性能,不管我复用池里面那个cell是不是你所想展示的那个cell,我都把它重排列一次。 重排列嘛,多大个事, 那我还不如把我之前的子视图给删掉了(移除),我重建一个全新的(因为cell的数据是要最新的,比如cell的hight )。最后再添加上去,这样就解决了。
1,移除UIButton
    给自定义添加的Button添加一个tag 。根据tag移除
2,创建新UIButton
     创建新Button的时候,我也添加相同的tag,为了下次复用的时候,好移除
3,  添加到cell
在这添加一行代码用于检验
[Objective-C] 纯文本查看 复制代码
- (void) checkR {
[[ selfviewWithTag:100] removeFromSuperview];
NSLog(@"听说你这个家伙要把我给组装一下????");
[ self  addButton];
}

-(void) addButton {
floath =20;
floatw = self.backgroundView.bounds.size.width ;
CGRectrect = CGRectMake(0,self.bounds.size.height-h, w, h);
UIButton *btn =  [[UIButton alloc] initWithFrame:rect];
btn.backgroundColor= [UIColor yellowColor];
btn.tag=100;
[self.contentViewa  ddSubview:btn];
}

理论上我们的问题应该解决了,那么我们来看一下运行的控制台


显示正常

    可以看出来,初始化的时候也进行重排了,这一点,我上说过,需要牺牲一点,做一点牺牲,但是只是对于有效屏幕的几个cell,这点牺牲是可忽略的。
    好了,故事写到这,也该结束了,我是正在自学的过程中,由于建的一个测试文档并且还没有参与正式的项目过,所以比较正规的命名和一些细节处理不是很规范,在这,也希望各位能留下点经验,或者指一指路。对于文中有理解不对的地方,希望各位能指出来。  处理这样类似的问题还有其他方法,我看过有弃掉重用机制的,即创建不同的复用ID等,就不阐述了,局限性很大,内存压力。
谢谢!

精华推荐:

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马