ios奇门杂招移动端开发ios牛掰控件

UICollectionView详解(二)—— 自定义UICol

2017-07-11  本文已影响356人  沐泽sunshine

在上一篇文章中,为大家介绍了UICollectionView的基本使用方法,过程和内容都比较简单,有兴趣看的同学可以点击这里,本次将为大家介绍的是如何使用UICollectionLayout自定义复杂的布局。

1、UICollectionViewLayout简介

(1)基本方法

在UICollectionViewLayout时,我们主要会重写它的以下几个方法

- (void)prepareLayout;

prepareLayout会在三个时机调用,第一次初始化layout的时候,刷新layout的时候以及方法- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds返回YES的时候

- (CGSize)collectionViewContentSize;

该方法返回collectionView的内容的大小

- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect; 

该方法会返回rect范围内所有cell的布局属性UICollectionViewLayoutAttributes

- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;

该方法返回对应indexPath下的cell的布局属性UICollectionViewLayoutAttributes

该方法返回在界面发生变化是是否要重新布局,返回YES则会重新布局
返回滑动后的collectonView的偏移量(滑动所停止的点),默认返回proposedContentOffset参数的值,在这里我们可以手动设置实际需要的偏移量
#####(2)UICollectionViewLayout与UICollectionViewFlowLayout
在此之前,我们先来简单的关注一下`UICollectionViewFlowLayout`和`UICollectionViewLayout`的关系:`UICollectionViewFlowLayout`是系统为我们封装的一个继承于`UICollectionViewLayout`的子类,系统已经写好了布局,所以如果我们在```- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect; 
```方法中调用  ``` NSArray *attributesArr = [super layoutAttributesForElementsInRect:rect];```,可以得到系统为我们写好的布局,但是如果直接继承于UICollectionViewLayout,上述方法得不到任何布局,所以我们必须要重写`- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;
`方法,在方法中写好布局并调用,这样才能为cell布局。

#####(3)UICollectionViewLayoutAttributes
关于cell的布局,我们还需要着重看一个类:UICollectionViewLayoutAttributes,它就是我们上面一直所说的cell的布局类,cell所有的布局属性都是要写到该类中的,那它到底都有哪些属性呢:

@property (nonatomic) CGRect frame;
@property (nonatomic) CGPoint center;
@property (nonatomic) CGSize size;
@property (nonatomic) CATransform3D transform3D;
@property (nonatomic) CGRect bounds );
@property (nonatomic) CGAffineTransform transform ;
@property (nonatomic) CGFloat alpha;
@property (nonatomic) NSInteger zIndex; // default is 0
@property (nonatomic, getter=isHidden) BOOL hidden;
@property (nonatomic, strong) NSIndexPath *indexPath;

改变了这些属性,并传递给layout,就可以改变cell的布局,所以归根到底,不管多复杂的布局,都是在改变这些属性。
###自定义UICollectionViewLayout具体实现
下面,我们就在具体的实例中看一下,如果使用自定义layout:
####先为大家贴出代码:
######创建一个继承于UICollectionViewLayout的子类
>.h

import <UIKit/UIKit.h>

@interface My_1Layout : UICollectionViewLayout
@end

>.m

import "My_1Layout.h"

@interface My_1Layout()
{
UIEdgeInsets _edgeInset;//内边距
CGFloat _lineSpacing;//行间距
CGFloat _columnsSpacing;//列间距
NSInteger _columnsNum;//列数
NSMutableArray *_columnsHeightArray;//用来存放所有列的高度
CGFloat _maxHeight;//collectionContent最大高度
}
@property (nonatomic,strong) NSMutableArray *attributesArray;//用来存放所有的cell的布局

@end

@implementation My_1Layout

大概思路就是:首先初始化layout的各种属性和变量,在- (void)prepareLayout中循环调用-(UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:方法,为所有的cell添加布局,最后从-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:中将其返回即可。本例中,

调用layout的方法也很简单,就正常创建layout,并赋给collectionView就可以了:

My_1Layout layout = [[My_1Layout alloc]init];
UICollectionView
collectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 64, kScreenWidth, kScreenHeight-64) collectionViewLayout:layout];

下面是效果图:
![效果图-1.gif](http:https://img.haomeiwen.com/i1914621/6c873fb7927b595e.gif?imageMogr2/auto-orient/strip)

(注:在开发中,对于需要在外部的控制器中设置layout属性的,包括内边距、行间距、列间距、列数以及cell的初始大小等,可以为layout添加代理,使用代理方法返回)。


下面我们再看一个例子:
首先,我们先创建一个继承于UICollectionViewFlowLayout的layout子类,layout类中不做任何实现,然后在控制器中赋值给collectionView,控制器中关于collectionView和数据源的设置和上例一样,然后运行程序,查看效果:
![效果图-2.PNG](http:https://img.haomeiwen.com/i1914621/315258ac335f087d.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

我们发现,尽管layout没有做任何布局,但是collectionView任然可以显示,这就说明,UICollectionViewFlowLayout已经为我们做好了一个布局,就是我们现在看到的流水布局,所以,对于继承于UICollectionViewFlowLayout的 类,如果要改变cell的布局,只需要获取系统默认为cell写好的布局,然后再此基础上进行修改就可以了。那么怎样获取UICollectionViewFlowLayout为我们写好的布局呢,使用父类调用-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:。

废话不多说,直接上代码:

/**
*prepareLayout会频繁调用,所以只做一些简单的初始化操作
*/

}
/**
*设置为YES,collectionView的显示范围发生变化时,就要刷新布局
*/
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{

return YES;

}
/**
*返回所有cell的布局属性
*/
-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
//获取UICollectionViweFlowLayout已经做好的布局
NSArray attrbutesArray = [super layoutAttributesForElementsInRect:rect];
//计算collectionView可视范围的中心点所对应的collectionView的x值
CGFloat centerX = self.collectionView.contentOffset.x + self.collectionView.frame.size.width * 0.5;
//以每个cell中心点到centerX的距离为参考,对cell进行缩放
for (UICollectionViewLayoutAttributes attributes in attrbutesArray) {
//cell的中心点到centerX的距离
CGFloat distance = ABS(attributes.center.x - centerX);
//根据distance计算cell的缩放比例
CGFloat scale = 1 - (distance / self.collectionView.frame.size.width);
//设置缩放比例
attributes.transform3D = CATransform3DMakeScale(scale, scale, scale);
}
// 返回调整之后的布局属性数组
return attrbutesArray;
}
/

效果图:

![效果图-3.gif](http:https://img.haomeiwen.com/i1914621/bc10257d76409d4d.gif?imageMogr2/auto-orient/strip)

###总结:
基本上到这里,UICollectionVew的使用就结束了,如何能够将UICollectionVew使用的更好,关键就在于怎样更好的运用UICollectionViewLayout和UICollectionViewFlowLayout,这才是UICollectionVew的精髓所在。

有兴趣的同学,可以移步到GitHub中下载[Demo](https://github.com/muzesunshine/UICollectionViewDemo),里面我为大家做了非常详细的注释。
上一篇下一篇

猜你喜欢

热点阅读