from:   http://www.tuicool.com/articles/vuyIriN

当我们使用系统自带的UICollectionViewFlowLayout无法实现我们的布局时,我们就可以考虑自定义layout。

所以,了解并学习一下自定义Layout是很有必要。

其实可以分三个步骤:

  1. 覆写prepareLayout方法,并在里面事先就计算好必要的布局信息并存储起来。
  2. 基于prepareLayout方法中的布局信息,使用collectionViewContentSize方法返回UICollectionView的内容尺寸。
  3. 使用layoutAttributesForElementsInRect:方法返回指定区域cell、Supplementary View和Decoration View的布局属性。

了解了自定义布局的三个主要步骤,我们来通过自定义布局的方式用UICollectionView实现grideView。当然,grideView使用 UICollectionViewFlowLayout 就可以轻易实现,这里我们只是学习了解一下自定义布局的过程,所以拿grideView这个经常用的来作为例子。

我们创建一个新的工程 BGCustomLayoutCollectionViewDemo 。然后创建一个UICollectionViewLayout的子类对象 BGGrideLayout ,它就是我们自定义layout对象。

在BGGrideLayout里面,我们首先覆写prepareLayout方法。

prepareLayout是专门用来准备布局的,在 prepareLayout 方法里面我们可以事先就计算后面要用到的布局信息并存储起来,防止后面方法多次计算,提高性能。例如,我们可以在此方法就计算好每个cell的属性、整个CollectionView的内容尺寸等等。此方法在布局之前会调用一次,之后只有在调用 invalidateLayout 、 shouldInvalidateLayoutForBoundsChange: 返回 YES 和 UICollectionView刷新 的时候才会调用。

而在BGGrideLayout的prepareLayout方法中,我们有两个目的:

一是获取对应indexPath的 UICollectionViewLayoutAttributes 对象,并存储到二维数组 layoutInfoArr 当中;

二是计算出内容尺寸并保存到全局变量 contentSize 当中。

代码如下:

- (void)prepareLayout{
[super prepareLayout];
NSMutableArray *layoutInfoArr = [NSMutableArray array];
NSInteger maxNumberOfItems = 0;
//获取布局信息
NSInteger numberOfSections = [self.collectionView numberOfSections];
for (NSInteger section = 0; section < numberOfSections; section++){
NSInteger numberOfItems = [self.collectionView numberOfItemsInSection:section];
NSMutableArray *subArr = [NSMutableArray arrayWithCapacity:numberOfItems];
for (NSInteger item = 0; item < numberOfItems; item++){
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:item inSection:section];
UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];
[subArr addObject:attributes];
}
if(maxNumberOfItems < numberOfItems){
maxNumberOfItems = numberOfItems;
}
//添加到二维数组
[layoutInfoArr addObject:[subArr copy]];
}
//存储布局信息
self.layoutInfoArr = [layoutInfoArr copy];
//保存内容尺寸
self.contentSize = CGSizeMake(maxNumberOfItems*(self.itemSize.width+self.interitemSpacing)+self.interitemSpacing, numberOfSections*(self.itemSize.height+self.lineSpacing)+self.lineSpacing);
}

在上面的代码中,我们看到了 UICollectionViewLayoutAttributes 这个类,这个类其实专门用来存储视图的内容,例如frame、size、apha、hiden等等,layout最后会拿着这些frame设置给对应的视图。 而上面代码中,获取 UICollectionViewLayoutAttributes 是通过 layoutAttributesForItemAtIndexPath: 方法

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
//每一组cell为一行
attributes.frame = CGRectMake((self.itemSize.width+self.interitemSpacing)*indexPath.row+self.interitemSpacing, (self.itemSize.height+self.lineSpacing)*indexPath.section+self.lineSpacing, self.itemSize.width, self.itemSize.height);
return attributes;
}

在这个方法中, itemSize 是cell的大小, interitemSpacing 是cell与cell之间的间距, lineSpacing 是行距。

随后,覆写collectionViewContentSize

collectionViewContentSize返回内容尺寸给UICollectionView。注意这个方法返回的尺寸是给UICollectionView这个继承于 UIScrollView 的视图作为 contentSize ,不是UICollectionView的视图尺寸。正是因为这一点,我们自定义layout如果想让它只能横向滑动,只需要将这个 size.height 设置成 collectionView.height 就行了。 这个方法会多次调用,所以最好是在prepareLayout里就计算好。 在BGGrideLayout类中,我们只需要返回前面计算好的内容尺寸就行了。

- (CGSize)collectionViewContentSize{
return self.contentSize;
}

最后,覆写layoutAttributesForElementsInRect:方法

此方法需要返回一组UICollectionViewLayoutAttributes类型对象。它代表着在这个指定的区域中,我们需要显示 cell 、 Supplementary View 和 Decoration View中哪些视图,而这些视图的属性则保存UICollectionViewLayoutAttributes中。 此方法会多次调用,为了更好的性能,在这个方法当中,我们使用的UICollectionViewLayoutAttributes最好是在prepareLayout已经布局好的信息。

在BGGrideLayout中,我们遍历二维数组,找出了与指定区域有交接的UICollectionViewLayoutAttributes对象放到一个数组中,然后返回。

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{
NSMutableArray *layoutAttributesArr = [NSMutableArray array];
[self.layoutInfoArr enumerateObjectsUsingBlock:^(NSArray *array, NSUInteger i, BOOL * _Nonnull stop) {
[array enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes *obj, NSUInteger idx, BOOL * _Nonnull stop) {
if(CGRectIntersectsRect(obj.frame, rect)) {
[layoutAttributesArr addObject:obj];
}
}];
}];
return layoutAttributesArr;
}

到这里,我们的BGGrideLayout已经写好了,使用部分的代码,请直接查看 BGCustomLayoutCollectionViewDemo 中ViewController里面的代码就行了。

自定义 Layout布局 UICollectionViewLayout的更多相关文章

  1. UICollectionView Layout自定义 Layout布局

    from:   http://www.tuicool.com/articles/vuyIriN 当我们使用系统自带的UICollectionViewFlowLayout无法实现我们的布局时,我们就可以 ...

  2. 自定义UICollectionLayout布局 —— UIKit之学习UICollectionView记录一《瀑布流》

    一.思路 思路一:比较每一行所有列的cell的高度,从上到下(也就是从第一行开始),从最短的开始计算,(记录下b的高度和索引,从开始计算,依次类推) 思路二:设置上.下.左.右间距和行间距.列间距及列 ...

  3. 获取 AlertDialog自定义的布局 的控件

    AlertDialog自定义的布局 效果图: 创建dialog方法的代码如下: 1 LayoutInflater inflater = getLayoutInflater(); 2 View layo ...

  4. [android] 手机卫士自定义对话框布局

    手机防盗页面部分 点击手机防盗,进行判断,如果没有设置密码,显示一个设置密码的对话框,如果已经设置密码了,弹出输入密码对话框 密码保存在SharedPreferences中,数据取出进行判断 自定义一 ...

  5. Android -- Layout布局文件里的android:layout_height等属性为什么会不起作用?

    有的时候,我们配置好的布局文件,在加载完成添加到我们的Activity中后发现,并没有安装我们设置的属性来布局,比如我们设置了android:layout_marginTop="100dip ...

  6. BootStrap入门教程 (一) :手脚架Scaffolding(全局样式(Global Style),格网系统(Grid System),流式格网(Fluid grid System),自定义(Customing),布局(Layouts))

    2011年,twitter的“一小撮”工程师为了提高他们内部的分析和管理能力,用业余时间为他们的产品构建了一套易用.优雅.灵活.可扩展的前端工具集--BootStrap.Bootstrap由MARK ...

  7. Android Layout布局文件里的android:layout_height等属性不起作用

    有的时候,我们配置好的布局文件,在加载完成添加到我们的Activity中后发现,并没有安装我们设置的属性 来布局,比为我们设置了android:layout_marginTop="100di ...

  8. iOS开发自定义流水布局

    //集成UICollectionViewFlowLayout 自己写的布局 //  SJBFlowLayout.m //  自定义流水布局 // //  Created by zyyt on 16/7 ...

  9. UICollectionView之自定义Layout

    #import <UIKit/UIKit.h> @interface WQViewController : UIViewController - (id)initWithFrame:(CG ...

随机推荐

  1. Spring mvc配置Json返回

    第一种 配置 <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHand ...

  2. 关于solaris中 crontab -e 出现数字0的解决办法

    解决方法: 通过网络,发现要设置编辑器的环境变量 $ EDITOR=vi  $ export EDITOR$ echo $EDITORvi$ crontab -e OK

  3. 如何在项目中引入MetaQ消息收发机制

    当需要异步发送和接收大量消息时,需要在Crystal项目中引入MetaQ消息收发机制. 关于MetaQ使用的官方例子可参考:https://github.com/killme2008/Metamorp ...

  4. HDU5835

    Danganronpa Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total ...

  5. SSM框架注解整合

    一.web应用环境 1.ServletContext 对于一个web应用,其部署在web容器(比如:tomcat)中,web容器提供其一个全局的上下文环境,这个上下文就是ServletContext, ...

  6. 使用PMD进行代码审查

    很久没写博客了,自从上次写的设计模式的博客被不知名的鹳狸猿下架了一次之后兴趣大减,那时候就没什么兴致写博客了,但是这段时间还没有停下来,最近也在研究一些其他的东西,目前有点想做点东西的打算,但好像也没 ...

  7. web前端 兼容性问题

    1:position属性使用过多或使用位置不恰当引起滚动时页面错乱 浏览器环境:ie7 position:relative; 网页上最直接表现就是极具破坏性的滚动错位,问题产生来自ie7自身渲染解析出 ...

  8. java实现简单的单点登录_转

    摘要:单点登录(SSO)的技术被越来越广泛地运用到各个领域的软件系统当中.本文从业务的角度分析了单点登录的需求和应用领域:从技术本身的角度分析了单点登录技术的内部机制和实现手段,并且给出Web-SSO ...

  9. linux虚拟机CentOS 7完整安装流程截图

    安装VMware虚拟机过程此处省略,只介绍在虚拟机上安装linux系统CentOS 7过程截图. 1 新建虚拟机 2 命名虚拟机,选择linux安装位置 3 选择虚拟机处理器数量和处理器核心数 4 分 ...

  10. 浅谈 MVC中的ViewData、ViewBag和TempData

    ViewBag和TempData的区别 ViewData ViewBag 它是Key/Value字典集合 它是dynamic类型对像 从Asp.net MVC 1 就有了 ASP.NET MVC3 才 ...