zoukankan      html  css  js  c++  java
  • 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

    效果图

    这里写图片描述 
    这里写图片描述

  • 相关阅读:
    BeautifulSoup的基本用法
    [leedcode 189] Rotate Array
    [leedcode 187] Repeated DNA Sequences
    [leedcode 179] Largest Number
    [leedcode 174] Dungeon Game
    [leedcode 173] Binary Search Tree Iterator
    [leedcode 172] Factorial Trailing Zeroes
    [leedcode 171] Excel Sheet Column Number
    [leedcode 169] Majority Element
    [leedcode 168] Excel Sheet Column Title
  • 原文地址:https://www.cnblogs.com/crash-wu/p/4924076.html
Copyright © 2011-2022 走看看