自定义流水布局(UICollectionViewFlowLayout的基本使用)

最终显示的效果图

思路:

1、UICollection的基本设置,并且创建一个继承自UICollectionViewFlowLayout的类。(不能是UICollectionViewLayout,否则全部都需要自定义)

2、在UICollectionViewFlowLayout类中完成四步

  - 1)重写prepareLayout方法进行基本的布局(cell在最左面的时候是在正中间),不能在init中布局,因为设置collectionView尺寸是在viewDidLoad中,而init在它之前调用,获得的collectionView的尺寸是空的

  - 2)重写shouldInvalidateLayoutForBoundsChange,当collectionView的显示范围发生改变的时候,让其内部重新布局(即让cell滚动起来)

  - 3)重写layoutAttributesForElementsInRect方法,让cell在左右滑动的时候,尺寸放大或缩小

  - 4)重写targetContentOffsetForProposedContentOffset方法,让最接近中心的cell在停在正中央。

 

代码如下:

viewContorller中:

 1 #import "ViewController.h"
 2 #import "ZWLineLayout.h"
 3 @interface ViewController () <UICollectionViewDataSource>
 4 @end
 5 @implementation ViewController
 6 static  NSString *ZWCellID = @"cell";
 7 - (void)viewDidLoad {
 8     [super viewDidLoad];
 9     //若为UICollectionViewLayout,itemSize和scrollDirection都需要自己写,下面的类继承自UICollectionViewLayout
10     ZWLineLayout *layout = [[ZWLineLayout alloc] init];
11     layout.itemSize = CGSizeMake(160, 160);
12     CGRect rect = CGRectMake(0, 100, self.view.frame.size.width, self.view.frame.size.width * 0.6);
13     UICollectionView *collection = [[UICollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
14     collection.dataSource = self;
15     collection.backgroundColor = [UIColor greenColor];
16     [self.view addSubview:collection];
17     [collection registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:ZWCellID];
18 }
19 
20 #pragma mark - 数据源方法
21 - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
22 {
23     return 10;
24 }
25 - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
26 {
27     UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ZWCellID forIndexPath:indexPath];
28     cell.backgroundColor = [UIColor orangeColor];
29     return cell;
30 }

ZWLineLayout.m中

 1 #import "ZWLineLayout.h"
 2 
 3 @implementation ZWLineLayout
 4 
 5 /**
 6  * 用来做布局的初始化操作(不建议在init方法中进行布局的初始化操作)
 7  */
 8 - (void)prepareLayout
 9 {
10     [super prepareLayout];
11     //水平滚动
12     self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
13     
14     //
15     CGFloat margin = (self.collectionView.frame.size.width - self.itemSize.width) / 2;
16     self.collectionView.contentInset = UIEdgeInsetsMake(0, margin, 0, margin);
17 }
18 
19 /**
20  * 当collectionView的显示范围发生改变的时候,是否需要重新刷新布局
21  * 一旦重新刷新布局,就会重新调用下面的方法:
22  * 1.prepareLayout
23  * 2.layoutAttributesForElementsInRect:方法
24  */
25 - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
26 {
27     return YES;
28 }
29 
30 
31 /**
32  * 这个方法的返回值是一个数组(数组里面存放着rect范围内所有元素的布局属性)
33  * 这个方法的返回值决定了rect范围内所有元素的排布(frame)
34  */
35 //需要在viewController中使用上ZWLineLayout这个类后才能重写这个方法!!
36 - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
37 {
38     //让父类布局好样式
39     NSArray *arr = [super layoutAttributesForElementsInRect:rect];
40     //计算出collectionView的中心的位置
41     CGFloat ceterX = self.collectionView.contentOffset.x + self.collectionView.frame.size.width * 0.5;
42     /**
43      * 1.一个cell对应一个UICollectionViewLayoutAttributes对象
44      * 2.UICollectionViewLayoutAttributes对象决定了cell的frame
45      */
46     for (UICollectionViewLayoutAttributes *attributes in arr) {
47         //cell的中心点距离collectionView的中心点的距离,注意ABS()表示绝对值
48         CGFloat delta = ABS(attributes.center.x - ceterX);
49         //设置缩放比例
50         CGFloat scale = 1.1 - delta / self.collectionView.frame.size.width;
51         //设置cell滚动时候缩放的比例
52         attributes.transform = CGAffineTransformMakeScale(scale, scale);
53     }
54     
55     return arr;
56 }
57 
58 /**
59  * 这个方法的返回值,就决定了collectionView停止滚动时的偏移量
60  */
61 - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
62 {
63     // 计算出最终显示的矩形框
64     CGRect rect;
65     rect.origin.y = 0;
66     rect.origin.x = proposedContentOffset.x;
67     rect.size = self.collectionView.frame.size;
68     
69     //获得super已经计算好的布局的属性
70     NSArray *arr = [super layoutAttributesForElementsInRect:rect];
71     
72     //计算collectionView最中心点的x值
73     CGFloat centerX = proposedContentOffset.x + self.collectionView.frame.size.width * 0.5;
74     
75     CGFloat minDelta = MAXFLOAT;
76     for (UICollectionViewLayoutAttributes *attrs in arr) {
77         if (ABS(minDelta) > ABS(attrs.center.x - centerX)) {
78             minDelta = attrs.center.x - centerX;
79         }
80     }
81     proposedContentOffset.x += minDelta;
82     return proposedContentOffset;
83 }
84 @end

 

posted @ 2016-07-31 18:33  hissia  阅读(7746)  评论(0编辑  收藏  举报