IOS開發--橫向流水布局實現,ios--橫向布局
前言:因為時間緣故,很少進行通俗易懂的演算法思路講解,這裡先展示動態圖片效果,然後後面的內容我就直接上關鍵源碼了。
效果展示圖;
源碼百度雲端硬碟下載連結: http://pan.baidu.com/s/1eQOOixc 密碼: duu8
源碼:
1 // PhotoCell.h 2 // 自訂流水布局 3 // 4 // Created by xmg on 16/1/15. 5 // Copyright © 2016年 HeYang. All rights reserved. 6 // 7 8 #import <UIKit/UIKit.h> 9 10 @interface PhotoCell : UICollectionViewCell11 12 @property (nonatomic, strong) UIImage *image;13 14 @end15 16 17 //18 // PhotoCell.m19 // 自訂流水布局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 @end32 33 @implementation PhotoCell34 35 - (void)awakeFromNib {36 // Initialization code37 }38 39 - (void)setImage:(UIImage *)image40 {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