你的位置:首页 > 操作系统

[操作系统]自定义流水布局(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都需要自己写,下面的类继承自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