iOS开发--横向流水布局实现
iOS开发--横向流水布局实现
前言:因为时间缘故,很少进行通俗易懂的算法思路讲解,这里先展示动态图片效果,然后后面的内容我就直接上关键源码了。
效果展示图;
源码百度云盘下载链接: http://pan.baidu.com/s/1eQOOixc 密码: duu8
源码:
1 // PhotoCell.h
2 // 自定义流水布局
3 //
6 //
7
8 #import <UIKit/UIKit.h>
9
10 @interface PhotoCell : UICollectionViewCell
11
12 @property (nonatomic, strong) UIImage *image;
13
14 @end
15
16 ================两个文件的分水岭==================
17 //
18 // PhotoCell.m
19 // 自定义流水布局
20 //
21 // Created by xmg on 16/1/15.
22 // Copyright © 2016年 HeYang. All rights reserved.
23 //
24
25
26
27 #import "PhotoCell.h"
28
29 @interface PhotoCell ()
30 @property (weak, nonatomic) IBOutlet UIImageView *imageView;
31 @end
32
33 @implementation PhotoCell
34
35 - (void)awakeFromNib {
36 // Initialization code
37 }
38
39 - (void)setImage:(UIImage *)image
40 {
41 _image = image;
42
43 _imageView.image = image;
44
45 }
46
47 @end
1 //
2 // PhotoLayout.h
3 // 自定义流水布局
4 //
5 // Created by xmg on 16/1/15.
6 // Copyright © 2016年 HeYang. All rights reserved.
7 //
8
9 #import <UIKit/UIKit.h>
10
11 @interface PhotoLayout : UICollectionViewFlowLayout
12
13 @end
14
15
16 ==============两个文件的分水岭================
17
18 //
19 // PhotoLayout.m
20 // 自定义流水布局
21 //
22 // Created by xmg on 16/1/15.
23 // Copyright © 2016年 HeYang. All rights reserved.
24 //
25
26 #import "PhotoLayout.h"
27 #define XMGScreenW [UIScreen mainScreen].bounds.size.width
28 @implementation PhotoLayout
29
30 // 复杂效果: 分析 ->
31 // cell离中心点距离越近(delta越小),就越大,越远,就越小
32 // 距离中心点
33 // 知道哪些cell需要缩放:显示出来的cell才需要进行布局
34
35
36
37 // 给定一个区域,就返回这个区域内所有cell布局
38 - (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
39 {
40 // 1.获取显示区域,bounds 而不是整个滚动区域,这样设置的子控件就控制在显示区域范围内了。
41 CGRect visiableRect = self.collectionView.bounds;
42
43 // 2.获取显示区域内的cell的布局
44 NSArray *attributes = [super layoutAttributesForElementsInRect:visiableRect];
45
46
47
48 // 3.遍历cell布局
49 CGFloat offsetX = self.collectionView.contentOffset.x;
50 for (UICollectionViewLayoutAttributes *attr in attributes) {
51 // 3.1 计算下距离中心点距离
52 CGFloat delta = fabs(attr.center.x - offsetX - XMGScreenW * 0.5);
53 // 1 ~ 0.75
54 CGFloat scale = 1 - delta / (XMGScreenW * 0.5) * 0.25;//1-(0~0.5) = 1~0.5 --> 1-(0~0.5)×0.25 = (1~0.75)
55 attr.transform = CGAffineTransformMakeScale(scale, scale);
56 }
57
58 return attributes;
59 }
60
61 // Invalidate:刷新
62 // 是否允许在拖动的时候刷新布局
63 // 谨慎使用,YES:只要一滚动就会布局
64 - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
65 {
66 return YES;
67 }
68
69 // 确定最终显示位置
70 // 什么时候调用:手动拖动UICollectionView,当手指离开的时候,就会调用
71 // 作用:返回UICollectionView最终的偏移量
72 // proposedContentOffset:最终的偏移量
73 - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
74 {
75 // 定位:判断下哪个cell里中心点越近,就定位到中间
76 // 1.获取最终显示的区域
77 CGRect targetRect = CGRectMake(proposedContentOffset.x, 0, self.collectionView.bounds.size.width, MAXFLOAT);
78
79 // 2.获取最终显示cell的布局
80 NSArray *attributes = [super layoutAttributesForElementsInRect:targetRect];
81
82 // 3.遍历所有cell的布局,判断下哪个离中心点最近
83 CGFloat minDelta = MAXFLOAT;
84
85 for (UICollectionViewLayoutAttributes *attr in attributes) {
86 // 3.1 计算下距离中心点距离
87 CGFloat delta = attr.center.x - proposedContentOffset.x - XMGScreenW * 0.5;
88 // 3.2 计算最小间距
89 if (fabs(delta) < fabs(minDelta)) {
90 minDelta = delta;
91 }
92 }
93
94 proposedContentOffset.x += minDelta;
95
96 if (proposedContentOffset.x < 0) {
97 proposedContentOffset.x = 0;
98 }
99
100 return proposedContentOffset;
101 }
102
103 @end
最后的关键代码:
1 //
2 // ViewController.m
3 // 自定义流水布局
4 //
5 // Created by xmg on 16/1/15.
6 // Copyright © 2016年 HeYang. All rights reserved.
7 //
8
9 #import "ViewController.h"
10 #import "PhotoCell.h"
11 #import "PhotoLayout.h"
12
13 /*
14 // a , b , c a = b + c
15 // int d = (2,3,5);
16
17 // 高聚合,低耦合
18 int a = ({
19 int b = 2;
20 int c = 3;
21 a = b + c;
22 20;
23 });
24 */
25
26 /*
27 UICollectionView注意点:
28 1.初始化必须要传入布局,(流水布局:九宫格布局)
29 2.UICollectionViewCell必须要注册
30 3.必须自定义cell
31 */
32
33
34 #define XMGScreenW [UIScreen mainScreen].bounds.size.width
35 static NSString * const ID = @"cell";
36 @interface ViewController ()<UICollectionViewDataSource>
37
38 @end
39
40 @implementation ViewController
41
42 // 思路:照片浏览布局:流水布局,在拖到的时候,在原来基础上重新计算下布局 -> 在原来功能上再添加功能,自定义流水布局
43 - (void)viewDidLoad {
44 [super viewDidLoad];
45 // Do any additional setup after loading the view, typically from a nib.
46
47 // 创建流水布局
48 PhotoLayout *layout = ({
49 layout = [[PhotoLayout alloc] init];
50 // 尺寸
51 layout.itemSize = CGSizeMake(180, 180);
52 // 设置滚动方向:水平
53 layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
54 // 设置额外滚动区域
55 CGFloat inset = (XMGScreenW - 180) * 0.5;
56 layout.sectionInset = UIEdgeInsetsMake(0, inset, 0, inset);
57
58 layout;
59 });
60
61 // 创建UICollectionView:默认为黑色
62 UICollectionView *collectionView = ({
63 collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
64 collectionView.bounds = CGRectMake(0, 0, self.view.bounds.size.width, 200);
65 collectionView.center = self.view.center;
66 collectionView.backgroundColor = [UIColor cyanColor];
67 collectionView.showsHorizontalScrollIndicator = NO;
68 [self.view addSubview:collectionView];
69
70 // 设置数据源
71 collectionView.dataSource = self;
72 collectionView;
73 });
74
75 // 注册cell
76 [collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([PhotoCell class]) bundle:nil] forCellWithReuseIdentifier:ID];
77 }
78
79
80 #pragma mark -UICollectionViewDataSource
81 // 返回有多少个cell
82 - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
83 {
84 return 20;
85 }
86
87 // 返回每个cell长什么样
88 - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
89 {
90
91 PhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ID forIndexPath:indexPath];
92
93 NSString *imageName = [NSString stringWithFormat:@"%ld",indexPath.row + 1];
94
95 cell.image = [UIImage imageNamed:imageName];
96
97 return cell;
98 }
99
100 @end

浙公网安备 33010602011771号