• UICollectionView左对齐流水布局、右对齐流水布局


        在平时使用的app中会经常碰到一些规格选择,筛选,标签等页面,这些页面的布局展示通常是左对齐流水布局。
    实现类似这样的左对齐流水布局有多种方式,如果选项少的话可以直接用UIButton实现。现在我们有一种比较简单的方式可以实现这个目的。
    就是对UICollectionView稍加改动,就能轻松实现。
    下面介绍一下具体实现的方法。

        通过 ZFFlowLayout类可以创建一个默认距离的布局实例,也可以创建一个自定义距离的布局实例。

    #import <UIKit/UICollectionViewFlowLayout.h>
    #import "ZFFlowLayoutMacro.h"
    #import "ZFFlowLayoutProtocol.h"
    
    //流水布局类型
    typedef enum : NSUInteger {
        FlowLayoutType_leftAlign,
        FlowLayoutType_rightAlign,
    } FlowLayoutType;
    
    @interface ZFFlowLayout : NSObject
    
    /*!
     *  @author zhoufei
     *
     *  @brief 根据传入不同的流失布局类型获取不同的布局实例
     *  @param flowLayoutType 流水布局类型
     *  @return 布局实例
     */
    + (UICollectionViewFlowLayout *)flowLayoutWithFlowLayoutType:(FlowLayoutType)flowLayoutType;
    
    
    /*!
     *  @author zhoufei
     *
     *  @brief 自定义布局实例:根据传入不同的流失布局类型,item距离四周距离,section距离四周距离 自定义布局实例
     *  @param flowLayoutType 流水布局类型
     *  @param itemEdgeInsets 第一个item距离四周的距离
     *  @param sectionEdgeInsets section距离四周的距离
     *  @return 布局实例
     */
    + (UICollectionViewFlowLayout<ZFFlowLayoutProtocol> *)flowLayoutWithFlowLayoutType:(FlowLayoutType)flowLayoutType
                                                                        ItemEdgeInsets:(FlowLayoutItemEdgeInsets)itemEdgeInsets
                                                                     sectionEdgeInsets:(FlowLayoutSectionEdgeInsets)sectionEdgeInsets;

    调用如下方法可以根据想要创建的布局类型,生成一个布局实现。

    + (UICollectionViewFlowLayout *)flowLayoutWithFlowLayoutType:(FlowLayoutType)flowLayoutType;

    调用如下方法可以根据想要创建的布局类型和第一个item距离四周的距离与section距离四周的距离,生成一个自定义的布局实现。

    + (UICollectionViewFlowLayout<ZFFlowLayoutProtocol> *)flowLayoutWithFlowLayoutType:(FlowLayoutType)flowLayoutType
                                                                        ItemEdgeInsets:(FlowLayoutItemEdgeInsets)itemEdgeInsets
                                                                     sectionEdgeInsets:(FlowLayoutSectionEdgeInsets)sectionEdgeInsets;

    在第二个方法中使用到了自定义的枚举和结构体,它们的具体实现如下:
    #ifndef ZFFlowLayoutMacro_h
    #define ZFFlowLayoutMacro_h
    
    /*!** 
     左对齐布局时:左上角第一个item 距离四周的距离
     右对齐布局时:右上角第一个item 距离四周的距离
      ***/
    typedef struct FlowLayoutItemEdgeInsets {
        CGFloat top, left, bottom, right;  // specify amount to inset (positive) for each of the edges. values can be negative to 'outset'
    } FlowLayoutItemEdgeInsets;
    
    /*!** item所属的组section 距离四周的距离 ***/
    typedef struct FlowLayoutSectionEdgeInsets {
        CGFloat top, left, bottom, right;  // specify amount to inset (positive) for each of the edges. values can be negative to 'outset'
    } FlowLayoutSectionEdgeInsets;
    
    #endif /* ZFFlowLayoutMacro_h */

    结构体中值得具体含义已经在注释中写出,这里就不在讲了。

    下面讲一下最核心的类 LeftAlignedFlowLayout类

    因为这个类代码略有点长,这里就这贴出主要的逻辑代码:

    - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
    {
        NSMutableArray* attributes = [[super layoutAttributesForElementsInRect:rect] mutableCopy];
        
        NSMutableArray * subArray = [LayoutAttributeTools groupTheSameLineItems:attributes];
    
        [self leftAlign_updateItemAttributeInSigleLine:subArray];
     
        return attributes;
    }
    
    /*!
     *  @author zhoufei
     *
     *  @brief 更新每个元素的位置
     *  @param groupArray 归并后的结果数组
     */
    - (void)leftAlign_updateItemAttributeInSigleLine:(NSMutableArray * )groupArray{
        
        NSMutableArray * modelArray = [NSMutableArray array];
        
        for (NSArray * array  in groupArray) {
            
            NSInteger count = array.count;
            
            if (!count) {
                continue;
            }
            
            for (int i = 0; i<count; i++) {
                UICollectionViewLayoutAttributes *attrOne = array[i];
                [modelArray addObject:[Attribute AttributeWithIndex:i attrOne.size.width]];
                
            }
            
            CGFloat leftWith = 0;
            
            for (int i=0; i<count; i++) {
                
                UICollectionViewLayoutAttributes *attr = [array objectAtIndex:i];
                
                NSPredicate *predice =[NSPredicate predicateWithFormat:@"index < %d",i];
                NSArray * resultArray = [modelArray filteredArrayUsingPredicate:predice];
                NSNumber * number = [resultArray valueForKeyPath:@"@sum.width"];
                
                leftWith = self.leftMargin+self.itemMargin*i+number.doubleValue;
                
                CGRect frame = attr.frame;
                frame.origin.x = leftWith;
                attr.frame = frame;
                
            }
            [modelArray removeAllObjects];
        }
        
    }

    上面这个方法
    - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
    是父类 UICollectionViewFlowLayout的代理方法,在这个方法中可以拿到当前屏幕中显示的所有 UICollectionViewCell的布局实现,我们对
    UICollectionViewCell的布局修改也就是在这个方法中。
    首先通过方法 [LayoutAttributeTools groupTheSameLineItems:attributes];对屏幕中显示的每一行 UICollectionViewCell 进行分组。这样分组之后逻辑比较清晰。只需要设置每一行UICollectionViewCell的新布局实例,剩余的也都是有每一行组成的。直接来个循环就搞定了。
    方法 [self leftAlign_updateItemAttributeInSigleLine:subArray];就是对分组后的UICollectionViewCell进行逐行更新布局实例对象的值。具体实现已经在代码中给出了。

    Demo地址:https://github.com/zhfei/ZFFlowLayout

      欢迎star。

      如果发现不对的地方欢迎批评和指正。

  • 相关阅读:
    题解 CF507A Amr and Music
    【NOIP 2020 游记--退役记】满船清梦压星河
    【CSP-2020 游记】
    【学习笔记】动态规划 DP
    【题解】洛谷 P5995 [PA2014]Lustra
    【题解】洛谷P6174 [USACO16JAN] Angry Cows S
    【题解】 洛谷 P6867 [COCI2019-2020#5] Politicari
    【题解】(LGJ原创)蝴蝶旅客
    【题解】洛谷 P6368 [COCI2006-2007#6] MAGIJA
    【题解】洛谷 P6484 [COCI2010-2011#4] ASTRO
  • 原文地址:https://www.cnblogs.com/zhou--fei/p/6905553.html
Copyright © 2020-2023  润新知