一、自定义布局【相册】
需求:
1.横向滚动
2.照片离中心点越近图片越大,即图片的放大和缩小
3.滚动停止时候总有一张照片居中显示
1、自定义布局 - 继承自UICollectionViewFlowLayout
重写prepareLayout方法
作用:在这个方法中做一些初始化的操作
注意:一定要调用[super prepareLayout]方法
2、重写layoutAttributesForElementsInRect:方法
作用 :
这个方法的返回值是个数组
这个数组中存放着的都是UICollectionViewLayoutAttribute对象
(1)一个cell对应一个UICollectionViewLayoutAttributes对象
(2)UICollectionViewLayoutAttribute对象决定了Cell的排布方式(frame)
3、重写shouldInvalidateLayoutForBoundsChange方法
作用 如果返回YES,那么CollectionView显示的范围发生改变的时候,就会重新刷新布局
一旦重新刷新布局,就会按顺序调用下面的方法:
prepareLayout
layoutAttributesForElementsInRect:
4、重写targetContentOffsetForProposedContentOffset:withScrollingVelocity:方法
-作用 返回值决定了collectionView停止滚动时最终的偏移量(contentOffset)
-参数:
-proposedContentOffset:原本情况下,collectionView停止滚动时最终的偏移量
-velocity:滚动速率,通过这个参数可以了解滚动的方向
#import "ViewController.h" #import "WXPhotoCell.h" #import "WXLineLayout.h" @interface ViewController ()<UICollectionViewDelegate,UICollectionViewDataSource> @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //创建布局 WXLineLayout *layout = [[WXLineLayout alloc]init]; layout.itemSize = CGSizeMake(150, 150); //创建CollectionView CGFloat collectionW = self.view.frame.size.width; CGFloat collectionH = 200; UICollectionView *WXCollectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 100, collectionW, collectionH) collectionViewLayout:layout]; WXCollectionView.delegate = self; WXCollectionView.dataSource = self; [self.view addSubview:WXCollectionView]; //注册 [WXCollectionView registerNib:[UINib nibWithNibName:NSStringFromClass([WXPhotoCell class]) bundle:nil] forCellWithReuseIdentifier:@"photoCell"]; } - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ return 5; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ WXPhotoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"photoCell" forIndexPath:indexPath]; if (!cell) { cell = [[WXPhotoCell alloc]init]; } cell.imageName = [NSString stringWithFormat:@"%zd",indexPath.item+1]; return cell; }
自定义布局WXLineLayout继承自UICollectionViewFlowLayout
缩放计算
算出collectionView和cell 中心点的间距
ABS(a-b)//取绝对值
// // WXLineLayout.m // 自定义流布局 // // Created by wangxu on 16/7/9. // Copyright © 2016年 Somebody. All rights reserved. // #import "WXLineLayout.h" @implementation WXLineLayout - (instancetype)init{ if (self = [super init]) { } return self; } /* 当collectionView的显示范围发生改变的时候,是否需要重新刷新布局 一旦重新刷新布局,就会调用下面两个方法 1.prepareLayout 2.layoutAttributesForElementsInRect:方法 */ - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{ return YES; } //用来做布局的初始化操作(不建议在init方法中进行布局的初始化操作) - (void)prepareLayout{ [super prepareLayout]; //设置水平滚动 self.scrollDirection = UICollectionViewScrollDirectionHorizontal; //设置内边距 CGFloat inset = (self.collectionView.frame.size.width-self.itemSize.width)*0.5; self.sectionInset = UIEdgeInsetsMake(0, inset, 0, inset); } /* UICollectionViewLayoutAttributes *attrs; 1.一个cell对应一个UICollectionViewLayoutAttributes对象 2.UICollectionViewLayoutAttributes对象决定了Cell的frame */ /* 这个方法的返回值是一个数组,(数组里存放着rect范围内所有元素的布局属性) 这个方法的返回值决定了rect范围内所有元素的排布(frame) */ - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect{ NSLog(@"======="); //获取super已经计算好的布局属性 NSArray * array = [super layoutAttributesForElementsInRect:rect]; //计算collectionView最中心的X值 CGFloat collectionCenterX = self.collectionView.contentOffset.x+self.collectionView.frame.size.width * 0.5; //在原有布局的基础上,进行微调 for (UICollectionViewLayoutAttributes *attrs in array) { //计算cell中心点X值 CGFloat cellX = attrs.center.x; //计算collectionView中心点X值和Cell中心点X值间的距离 CGFloat delta = ABS(cellX-collectionCenterX); //根据间距计算 cell的缩放比例 CGFloat scale = 1 - delta/self.collectionView.frame.size.width; //设置缩放比例 attrs.transform = CGAffineTransformMakeScale(scale, scale); } return array; } /* 这个方法的返回值,决定了colletionView停止滚动时的偏移量 */ - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity{ //计算出最终显示的矩形框 CGRect rect; rect.origin.x = proposedContentOffset.x; rect.origin.y = 0; rect.size = self.collectionView.frame.size; //获取滚动结束后super已经计算好的布局属性 NSArray *array = [super layoutAttributesForElementsInRect:rect]; //计算collectionView最中心点的X值 CGFloat collectionCenterX = self.collectionView.frame.size.width*0.5 + proposedContentOffset.x; //存放最小的间距 CGFloat minDelta = MAXFLOAT; for (UICollectionViewLayoutAttributes *attrs in array) { if (ABS(minDelta)>ABS(attrs.center.x-collectionCenterX)) { minDelta = attrs.center.x-collectionCenterX; } } //修改原有的偏移量 proposedContentOffset.x+=minDelta; return proposedContentOffset; } @end
自定义UICollectionViewCell
// // WXPhotoCell.h // 自定义流布局 // // Created by wangxu on 16/7/9. // Copyright © 2016年 Somebody. All rights reserved. // #import <UIKit/UIKit.h> @interface WXPhotoCell : UICollectionViewCell /** 图片名*/ @property (nonatomic, copy) NSString *imageName; @end
// // WXPhotoCell.m // 自定义流布局 // // Created by wangxu on 16/7/9. // Copyright © 2016年 Somebody. All rights reserved. // #import "WXPhotoCell.h" @interface WXPhotoCell () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @end @implementation WXPhotoCell - (void)awakeFromNib { [super awakeFromNib]; //设置照片的白色边框 self.imageView.layer.borderWidth = 5; self.imageView.layer.borderColor = [UIColor whiteColor].CGColor; } - (void)setImageName:(NSString *)imageName{ //设置cell的图片 _imageName = [imageName copy]; self.imageView.image = [UIImage imageNamed:imageName]; } @end
新手上路,还请大神们多多指教。
致谢MJ老师。