自訂流水布局(UICollectionViewFlowLayout的基本使用),flowlayout垂直布局
最終顯示的
思路:
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都需要自己寫,下面的類繼承自UICollectionViewLayout10 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)section22 {23 return 10;24 }25 - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath26 {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.prepareLayout23 * 2.layoutAttributesForElementsInRect:方法24 */25 - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds26 {27 return YES;28 }29 30 31 /**32 * 這個方法的傳回值是一個數組(數組裡面存放著rect範圍內所有元素的布局屬性)33 * 這個方法的傳回值決定了rect範圍內所有元素的排布(frame)34 */35 //需要在viewController中使用上ZWLineLayout這個類後才能重寫這個方法!!36 - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect37 {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的frame45 */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)velocity62 {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