美文网首页IOSIOS开发ios开发笔记
UICollectionView几种简单布局(线性,圆形,商品)

UICollectionView几种简单布局(线性,圆形,商品)

作者: 呆子是只喵 | 来源:发表于2016-05-18 16:25 被阅读2966次

    概述

    上一篇博客中,简单了解了一下 UICollectionView的构成和使用,在这篇文章中我们来学习一下几种经典的布局,在这之前我们需要来了解一个比较重要的类

    UICollectionViewLayoutAttributes

    UICollectionViewLayoutAttributes是一个非常重要的类,由他提供给 cell各种属性,看一下其有哪些重要的属性:

    • @property (nonatomic) CGRect frame; // 大小
    • @property (nonatomic) CGPoint center; // 中心位置
    • @property (nonatomic) CGSize size; // 形状
    • @property (nonatomic) CATransform3D transform3D; // 3D 动画
    • @property (nonatomic) CGRect bounds NS_AVAILABLE_IOS(7_0); //尺寸
    • @property (nonatomic) CGAffineTransform transform NS_AVAILABLE_IOS(7_0); // 形变
    • @property (nonatomic) CGFloat alpha; // 透明度
    • @property (nonatomic, getter=isHidden) BOOL hidden; // As an optimization, UICollectionView might not create a view for items whose hidden attribute is YES
      从上面可以看出,其实一个 cell 对应一个UICollectionViewLayoutAttributes对象,这个对象决定了cell 的 fram 等属性

    线性布局

    线性布局.png

    从图片来看,图片可以左右滑动,并且停留在屏幕最中间的 cell 会自动放大,这个简单的效果,让我们来看看是如何实现的
    首先,我们来考虑用系统的流水布局来实现这个效果,随后发现系统并没有提供相关 API, 接下来需要我们自定义一个线性布局,这个布局继承自系统提供的流水布局
    ** 用来做布局的初始化操作**

      - (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);
    }
    

    ** 返回一个数组,数组内存放着 rect 范围内所有元素的排布**

      - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
    {
        // 获得super已经计算好的布局属性
        NSArray *array = [super layoutAttributesForElementsInRect:rect];
        
        // 计算collectionView最中心点的x值
        CGFloat centerX = self.collectionView.contentOffset.x + self.collectionView.frame.size.width * 0.5;
        
        // 在原有布局属性的基础上,进行微调
        for (UICollectionViewLayoutAttributes *attrs in array) {
            // cell的中心点x 和 collectionView最中心点的x值 的间距
            CGFloat delta = ABS(attrs.center.x - centerX);
            
            // 根据间距值 计算 cell的缩放比例
            CGFloat scale = 1 - delta / self.collectionView.frame.size.width;
            
            // 设置缩放比例
            attrs.transform = CGAffineTransformMakeScale(scale, scale);
        }
        
        return array;
    }
    

    返回值决定了 collectionVIew 停止滚动时的偏移量

      - (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
    {
        // 计算出最终显示的矩形框
        CGRect rect;
        rect.origin.y = 0;
        rect.origin.x = proposedContentOffset.x;
        rect.size = self.collectionView.frame.size;
        
        // 获得super已经计算好的布局属性
        NSArray *array = [super layoutAttributesForElementsInRect:rect];
        
        // 计算collectionView最中心点的x值
        CGFloat centerX = proposedContentOffset.x + self.collectionView.frame.size.width * 0.5;
        
        // 存放最小的间距值
        CGFloat minDelta = MAXFLOAT;
        for (UICollectionViewLayoutAttributes *attrs in array) {
            if (ABS(minDelta) > ABS(attrs.center.x - centerX)) {
                minDelta = attrs.center.x - centerX;
            }
        }
        
        // 修改原有的偏移量
        proposedContentOffset.x += minDelta;
        return proposedContentOffset;
    }
    

    ** 需要注意的是,当 collectionView的显示范围发生变化时,会调用此方法来决定是否重新刷新 UI**

      - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
    {
        return YES;
    }```
    ***
    # 商品展示
    
    ![商品展示.png](https://img.haomeiwen.com/i694552/031730fcd9981e45.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    ** 商品展示效果可以上下滑动,图片交错排布,这个布局需要继承自UICollectionViewLayout(其实流水布局就继承自他),因为我们不需要流水布局为我们计算一些布局**
    **懒加载一个数组,里面存放着布局属UICollectionViewLayoutAttributes**
    
    • (NSMutableArray *)attrsArray
      {
      if (!_attrsArray) {
      _attrsArray = [NSMutableArray array];
      }
      return _attrsArray;
      }```

    ** 准备工作,计算好返回的属性**

      - (void)prepareLayout
    {
        [super prepareLayout];
        
        [self.attrsArray removeAllObjects];
        
        NSInteger count = [self.collectionView numberOfItemsInSection:0];
        for (int i = 0; i < count; i++) {
            // 创建UICollectionViewLayoutAttributes
            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
            UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
            
            // 设置布局属性
            CGFloat width = self.collectionView.frame.size.width * 0.5;
            if (i == 0) {
                CGFloat height = width;
                CGFloat x = 0;
                CGFloat y = 0;
                attrs.frame = CGRectMake(x, y, width, height);
            } else if (i == 1) {
                CGFloat height = width * 0.5;
                CGFloat x = width;
                CGFloat y = 0;
                attrs.frame = CGRectMake(x, y, width, height);
            } else if (i == 2) {
                CGFloat height = width * 0.5;
                CGFloat x = width;
                CGFloat y = height;
                attrs.frame = CGRectMake(x, y, width, height);
            } else if (i == 3) {
                CGFloat height = width * 0.5;
                CGFloat x = 0;
                CGFloat y = width;
                attrs.frame = CGRectMake(x, y, width, height);
            } else if (i == 4) {
                CGFloat height = width * 0.5;
                CGFloat x = 0;
                CGFloat y = width + height;
                attrs.frame = CGRectMake(x, y, width, height);
            } else if (i == 5) {
                CGFloat height = width;
                CGFloat x = width;
                CGFloat y = width;
                attrs.frame = CGRectMake(x, y, width, height);
            } else {
                UICollectionViewLayoutAttributes *lastAttrs = self.attrsArray[i - 6];
                CGRect lastFrame = lastAttrs.frame;
                lastFrame.origin.y += 2 * width;
                attrs.frame = lastFrame;
            }
            
            // 添加UICollectionViewLayoutAttributes
            [self.attrsArray addObject:attrs];
        }
    }
    

    ** 显示范围内的属性**

      - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
    {
        return self.attrsArray;
    }
    

    ** collectionview 的内容大小**

      - (CGSize)collectionViewContentSize
    {
        int count = (int)[self.collectionView numberOfItemsInSection:0];
        int rows = (count + 3 - 1) / 3;
        CGFloat rowH = self.collectionView.frame.size.width * 0.5;
        return CGSizeMake(0, rows * rowH);
    }
    

    圆形布局

    圆形布局.png

    ** 这是一个圆形布局,自定义UICollectionViewLayout实现**

    /** 布局属性 */
    @property (nonatomic, strong) NSMutableArray *attrsArray;
    @end
    
    @implementation XMGCircleLayout
    
    - (NSMutableArray *)attrsArray
    {
        if (!_attrsArray) {
            _attrsArray = [NSMutableArray array];
        }
        return _attrsArray;
    }
    
    - (void)prepareLayout
    {
        [super prepareLayout];
        
        [self.attrsArray removeAllObjects];
        
        NSInteger count = [self.collectionView numberOfItemsInSection:0];
        for (int i = 0; i < count; i++) {
            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
            UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:indexPath];
            [self.attrsArray addObject:attrs];
        }
    }
    
    - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
    {
        return self.attrsArray;
    }
    
    /**
     * 这个方法需要返回indexPath位置对应cell的布局属性
     */
    - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
    {
        NSInteger count = [self.collectionView numberOfItemsInSection:0];
        CGFloat radius = 70;
        // 圆心的位置
        CGFloat oX = self.collectionView.frame.size.width * 0.5;
        CGFloat oY = self.collectionView.frame.size.height * 0.5;
        
        UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
        
        attrs.size = CGSizeMake(50, 50);
        if (count == 1) {
            attrs.center = CGPointMake(oX, oY);
        } else {
            CGFloat angle = (2 * M_PI / count) * indexPath.item;
            CGFloat centerX = oX + radius * sin(angle);
            CGFloat centerY = oY + radius * cos(angle);
            attrs.center = CGPointMake(centerX, centerY);
        }
        
        return attrs;
    }
    

    相关文章

      网友评论

      本文标题:UICollectionView几种简单布局(线性,圆形,商品)

      本文链接:https://www.haomeiwen.com/subject/yjcwrttx.html