自定义流布局

一、自定义布局【相册】

需求:

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老师。

 

posted on 2016-07-10 18:00  Somebodywx  阅读(273)  评论(0编辑  收藏  举报