UICollectionViewFlowLayout 流水布局

Model cell

@interface ImageCell : UICollectionViewCell
@property (nonatomic, copy) NSString *image;
@end
@interface ImageCell()
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@end

@implementation ImageCell

- (void)awakeFromNib {
    self.imageView.layer.borderWidth = 3;
    self.imageView.layer.borderColor = [UIColor whiteColor].CGColor;
    self.imageView.layer.cornerRadius = 3;
    self.imageView.clipsToBounds = YES;
}

- (void)setImage:(NSString *)image
{
    _image = [image copy];

    self.imageView.image = [UIImage imageNamed:image];
}

@end

LineLayout

#import "LineLayout.h"

static const CGFloat ItemWH = 100;

@implementation LineLayout

- (instancetype)init
{
    if (self = [super init]) {
    }
    return self;
}

/**
 *  只要显示的边界发生改变就重新布局:
 内部会重新调用prepareLayout和layoutAttributesForElementsInRect方法获得所有cell的布局属性
 */
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
    return YES;
}

/**
 *  用来设置collectionView停止滚动那一刻的位置
 *
 *  @param proposedContentOffset 原本collectionView停止滚动那一刻的位置
 *  @param velocity              滚动速度
 */
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{
    // 1.计算出scrollView最后会停留的范围
    CGRect lastRect;
    lastRect.origin = proposedContentOffset;
    lastRect.size = self.collectionView.frame.size;

    // 计算屏幕最中间的x
    CGFloat centerX = proposedContentOffset.x + self.collectionView.frame.size.width * 0.5;

    // 2.取出这个范围内的所有属性
    NSArray *array = [self layoutAttributesForElementsInRect:lastRect];

    // 3.遍历所有属性
    CGFloat adjustOffsetX = MAXFLOAT;
    for (UICollectionViewLayoutAttributes *attrs in array) {
        if (ABS(attrs.center.x - centerX) < ABS(adjustOffsetX)) {
            adjustOffsetX = attrs.center.x - centerX;
        }
    }

    return CGPointMake(proposedContentOffset.x + adjustOffsetX, proposedContentOffset.y);
}

/**
 *  一些初始化工作最好在这里实现
 */
- (void)prepareLayout
{
    [super prepareLayout]; 

    // 每个cell的尺寸
    self.itemSize = CGSizeMake(ItemWH, ItemWH);
    CGFloat inset = (self.collectionView.frame.size.width - ItemWH) * 0.5;
    self.sectionInset = UIEdgeInsetsMake(0, inset, 0, inset);
    // 设置水平滚动
    self.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    self.minimumLineSpacing = ItemWH * 0.7;

    // 每一个cell(item)都有自己的UICollectionViewLayoutAttributes
    // 每一个indexPath都有自己的UICollectionViewLayoutAttributes
}

/** 有效距离:当item的中间x距离屏幕的中间x在ActiveDistance以内,才会开始放大, 其它情况都是缩小 */
static CGFloat const ActiveDistance = 150;
/** 缩放因素: 值越大, item就会越大 */
static CGFloat const ScaleFactor = 0.6;

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    // 0.计算可见的矩形框
    CGRect visiableRect;
    visiableRect.size = self.collectionView.frame.size;
    visiableRect.origin = self.collectionView.contentOffset;

    // 1.取得默认的cell的UICollectionViewLayoutAttributes
    NSArray *array = [super layoutAttributesForElementsInRect:rect];
    // 计算屏幕最中间的x
    CGFloat centerX = self.collectionView.contentOffset.x + self.collectionView.frame.size.width * 0.5;

    // 2.遍历所有的布局属性
    for (UICollectionViewLayoutAttributes *attrs in array) {
        // 如果不在屏幕上,直接跳过
        if (!CGRectIntersectsRect(visiableRect, attrs.frame)) continue;

        // 每一个item的中点x
        CGFloat itemCenterX = attrs.center.x;

        // 差距越小, 缩放比例越大
        // 根据跟屏幕最中间的距离计算缩放比例
        CGFloat scale = 1 + ScaleFactor * (1 - (ABS(itemCenterX - centerX) / ActiveDistance));
        attrs.transform = CGAffineTransformMakeScale(scale, scale);
    }

    return array;
}

@end

ViewController

#import "ViewController.h"
#import "ImageCell.h"
#import "LineLayout.h"

@interface ViewController () <UICollectionViewDataSource, UICollectionViewDelegate>
@property (nonatomic, strong) NSMutableArray *images;
@property (nonatomic, weak) UICollectionView *collectionView;
@end

@implementation ViewController

static NSString *const ID = @"image";

- (NSMutableArray *)images
{
    if (!_images) {
        self.images = [[NSMutableArray alloc] init];

        for (int i = 1; i<=20; i++) {
            [self.images addObject:[NSString stringWithFormat:@"%d", i]];
        }
    }
    return _images;
}

- (void)viewDidLoad {
    [super viewDidLoad];

    CGFloat w = self.view.frame.size.height;
    CGRect rect = CGRectMake(0, 0, w, 200);
    UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:rect collectionViewLayout:[[LineLayout alloc] init]];
    collectionView.dataSource = self;
    collectionView.delegate = self;
    [collectionView registerNib:[UINib nibWithNibName:@"ImageCell" bundle:nil] forCellWithReuseIdentifier:ID];
    [self.view addSubview:collectionView];
    self.collectionView = collectionView;
    // collectionViewLayout :
    // UICollectionViewLayout
    // UICollectionViewFlowLayout
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    if ([self.collectionView.collectionViewLayout isKindOfClass:[LineLayout class]]) {
        [self.collectionView setCollectionViewLayout:[[UICollectionViewFlowLayout alloc] init] animated:YES];
    } else {
        [self.collectionView setCollectionViewLayout:[[LineLayout alloc] init] animated:YES];
    }
}

#pragma mark - <UICollectionViewDataSource>
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return self.images.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    ImageCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ID forIndexPath:indexPath];
    cell.image = self.images[indexPath.item];
    return cell;
}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    // 删除模型数据
    [self.images removeObjectAtIndex:indexPath.item];

    // 删UI(刷新UI)
    [collectionView deleteItemsAtIndexPaths:@[indexPath]];
}

@end

效果图

 

时间: 2024-08-02 11:00:45

UICollectionViewFlowLayout 流水布局的相关文章

iOS开发 - UICollectionViewFlowLayout 流水布局

Model cell @interface ImageCell : UICollectionViewCell @property (nonatomic, copy) NSString *image; @end @interface ImageCell() @property (weak, nonatomic) IBOutlet UIImageView *imageView; @end @implementation ImageCell - (void)awakeFromNib { self.im

iOS开发——高级篇——流水布局UICollectionViewFlowLayout的基本使用

之前看到过的一篇文章 对collectionView的使用总结的非常好:“iOS6新特征:UICollectionView介绍” 流水布局在现在的应用中很常见了,简单的研究了下,实现下面的功能 那我这里就简单介绍下 UICollectionViewFlowLayout 常用的几个方法,通过这几个方法就能办到上面的效果了 1.布局 /** * 用来做布局的初始化操作(不建议在init方法中进行布局的初始化操作) */ - (void)prepareLayout { [super prepareLa

流水布局与block深入研究

9.  自定义流水布局 9.0UICollectionView与UItableView的区别:在布局(UItableView继承UISorllView),UICollectionView不用设置contentSize           9.0UICollectionView与UItableView的相同点:循环利用              9.1.0UICollectionView注意点:1.初始化必须要传入布局,(流水布局:九宫格布局)2.UICollectionViewCell必须注册3

瀑布流/流水布局的解决方案

1.最近做的一个项目用到了流水布局,简单粗暴,找了个demo放进去.刚开始静态页面感觉还不错. demo: http://www.cocoachina.com/ios/20160407/15872.html demo图 最关键的是图片下面还有4个label和一个imageView, 修改demo里的原始布局,让图片和文字高度自适应 图片和文字都没设置高度. 问题一:加载网络图片的时候,下拉刷新,图片高度和文字高度发生变化. 解决方案:计算文字的高度,文字高度固定后,刷新时布局不会发生改变. 计算

UICollectionView中使用 UICollectionViewFlowLayout进行布局(模仿苹果相册)

现在都知道,在初始化UICollectionView的时候,必须要传入一Layout对象,进行布局管理.这也是collectionview和tableview的明显区别,通过collectionviewLayout,可以对collectionview进行更加强有力的控制. 自定义个UICollectionViewFlowLayout,重新里面的几个方法. 方法一: 每次滑动collectionview都会调用此方法,询问是否重新layout.如果returen Yes:则会调用方法二和方法三.

自己总结的 iOS ,Mac 开源项目以及库,知识点------持续更新

自己在 git  上看到一个非常好的总结的东西,但是呢, fork  了几次,就是 fork  不到我的 git 上,干脆复制进去,但是,也是认真去每一个每一个去认真看了,并且也是补充了一些,感觉非常棒,所以好东西要分享,为啥用 CN 博客,有个好处,可以随时修改,可以持续更新,不用每次都要再发表,感觉这样棒棒的 我们 自己总结的iOS.mac开源项目及库,持续更新.... github排名 https://github.com/trending,github搜索:https://github.

iOS、mac开源项目及库汇总

UI 下拉刷新 EGOTableViewPullRefresh – 最早的下拉刷新控件. SVPullToRefresh – 下拉刷新控件. MJRefresh – 仅需一行代码就可以为UITableView或者CollectionView加上下拉刷新或者上拉刷新功能.可以自定义上下拉刷新的文字说明.具体使用看“使用方法”. (国人写) XHRefreshControl – XHRefreshControl 是一款高扩展性.低耦合度的下拉刷新.上提加载更多的组件.(国人写) CBStoreHou

最全面的iOS和Mac开源项目和第三方库汇总

UI 下拉刷新 EGOTableViewPullRefresh – 最早的下拉刷新控件. SVPullToRefresh – 下拉刷新控件. MJRefresh – 仅需一行代码就可以为UITableView或者CollectionView加上下拉刷新或者上拉刷新功能.可以自定义上下拉刷新的文字说明.具体使用看“使用方法”. (国人写) XHRefreshControl – XHRefreshControl 是一款高扩展性.低耦合度的下拉刷新.上提加载更多的组件.(国人写) CBStoreHou

UICollectionView基本使用详解(OC)

概述 UICollectionView是从iOS6开始引入使用的,目前应用非常广泛,很牛逼!老外的博客也是这么说的(传送门) ## 与UITableView的初步比较 UITableView应该是大家最熟悉的控件了,UICollectionView的使用与之类似,但又有所区别,如下介绍.相同点: 1.都是通过datasource和delegate驱动的(datasource和delegate官方文档传送),因此在使用的时候必须实现数据源与代理协议方法; 2.性能上都实现了循环利用的优化. 不同点