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 width: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。

  如果發現不對的地方歡迎批評和指正。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM