iOS開發--橫向流水佈局實現算法
前言:由於時間緣故,不多進行通俗易懂的算法思路講解,這裏先展現動態圖片效果,而後後面的內容我就直接上關鍵源碼了。佈局
效果展現圖;atom
源碼百度雲盤下載連接: http://pan.baidu.com/s/1eQOOixc 密碼: duu8spa
源碼:code
1 // PhotoCell.horm
2 // 自定義流水佈局blog
3 //圖片
6 //ci
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