在平時使用的app中會常常碰到一些規格選擇,篩選,標籤等頁面,這些頁面的佈局展現一般是左對齊流水佈局。
實現相似這樣的左對齊流水佈局有多種方式,若是選項少的話能夠直接用UIButton實現。如今咱們有一種比較簡單的方式能夠實現這個目的。
就是對UICollectionView稍加改動,就能輕鬆實現。
下面介紹一下具體實現的方法。git
經過 ZFFlowLayout類能夠建立一個默認距離的佈局實例,也能夠建立一個自定義距離的佈局實例。github
#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距離四周的距離,生成一個自定義的佈局實現。app
+ (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類spa
由於這個類代碼略有點長,這裏就這貼出主要的邏輯代碼:代理
- (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。code
若是發現不對的地方歡迎批評和指正。orm