码迷,mamicode.com
首页 > 其他好文 > 详细

9 - 瀑布流 - 这才是实现"瀑布流"效果最行之有效的办法

时间:2016-04-30 00:55:06      阅读:261      评论:0      收藏:0      [点我收藏+]

标签:

首先, 对于瀑布流的实现大体分为tableView和collectionView实现两种, 以collectionView实现最为简单. 本文对流行的实现方式进行改进, 减少依赖,增加更多代理方法,增加扩展性

 

 1 //
 2 //  AYWaterFlowLayout.h
 3 //  AY瀑布流
 4 //
 5 //  Created by Jasper on 16/1/25.
 6 //  Copyright © 2016年 Jasper. All rights reserved.
 7 //
 8 
 9 #import <UIKit/UIKit.h>
10 
11 @class AYWaterFlowLayout;
12 
13 @protocol AYWaterFlowLayoutDelegate <NSObject>
14 @required
15 - (CGFloat)waterflowLayout:(AYWaterFlowLayout *)waterflowLayout heightForItemAtIndex:(NSUInteger)index itemWidth:(CGFloat)itemWidth;
16 
17 @optional
18 - (CGFloat)columnCountInWaterflowLayout:(AYWaterFlowLayout *)waterflowLayout;
19 - (CGFloat)columnMarginInWaterflowLayout:(AYWaterFlowLayout *)waterflowLayout;
20 - (CGFloat)rowMarginInWaterflowLayout:(AYWaterFlowLayout *)waterflowLayout;
21 - (UIEdgeInsets)edgeInsetsInWaterflowLayout:(AYWaterFlowLayout *)waterflowLayout;
22 @end
23 
24 
25 @interface AYWaterFlowLayout : UICollectionViewLayout
26 /** 代理 */
27 @property (nonatomic, weak) id<AYWaterFlowLayoutDelegate> delegate;
28 @end
  1 //
  2 //  AYWaterFlowLayout.m
  3 //  AY瀑布流
  4 //
  5 //  Created by Jasper on 16/1/25.
  6 //  Copyright © 2016年 Jasper. All rights reserved.
  7 //
  8 
  9 #import "AYWaterFlowLayout.h"
 10 
 11 
 12 /** 默认的列数 */
 13 static const NSInteger AYDefaultColumnCount = 3;
 14 /** 每一列之间的间距 */
 15 static const CGFloat AYDefaultColumnMargin = 10;
 16 /** 每一行之间的间距 */
 17 static const CGFloat AYDefaultRowMargin = 10;
 18 /** 边缘间距 */
 19 static const UIEdgeInsets AYDefaultEdgeInsets = {10, 10, 10, 10};
 20 
 21 
 22 
 23 
 24 
 25 @interface AYWaterFlowLayout ()
 26 
 27 /** 存放所有cell的布局属性 */
 28 @property (nonatomic, strong) NSMutableArray *attrsArray;
 29 /** 存放所有列的当前高度 */
 30 @property (nonatomic, strong) NSMutableArray *columnHeights;
 31 /** 内容的高度 */
 32 @property (nonatomic, assign) CGFloat contentHeight;
 33 
 34 
 35 - (CGFloat)rowMargin;
 36 - (CGFloat)columnMargin;
 37 - (NSInteger)columnCount;
 38 - (UIEdgeInsets)edgeInsets;
 39 
 40 @end
 41 
 42 
 43 @implementation AYWaterFlowLayout
 44 
 45 #pragma mark - 常见数据处理
 46 - (CGFloat)rowMargin
 47 {
 48     if ([self.delegate respondsToSelector:@selector(rowMarginInWaterflowLayout:)]) {
 49         return [self.delegate rowMarginInWaterflowLayout:self];
 50     } else {
 51         return AYDefaultRowMargin;
 52     }
 53 }
 54 
 55 - (CGFloat)columnMargin
 56 {
 57     if ([self.delegate respondsToSelector:@selector(columnMarginInWaterflowLayout:)]) {
 58         return [self.delegate columnMarginInWaterflowLayout:self];
 59     } else {
 60         return AYDefaultColumnMargin;
 61     }
 62 }
 63 
 64 - (NSInteger)columnCount
 65 {
 66     if ([self.delegate respondsToSelector:@selector(columnCountInWaterflowLayout:)]) {
 67         return [self.delegate columnCountInWaterflowLayout:self];
 68     } else {
 69         return AYDefaultColumnCount;
 70     }
 71 }
 72 
 73 - (UIEdgeInsets)edgeInsets
 74 {
 75     if ([self.delegate respondsToSelector:@selector(edgeInsetsInWaterflowLayout:)]) {
 76         return [self.delegate edgeInsetsInWaterflowLayout:self];
 77     } else {
 78         return AYDefaultEdgeInsets;
 79     }
 80 }
 81 
 82 #pragma mark - 懒加载
 83 - (NSMutableArray *)columnHeights
 84 {
 85     if (!_columnHeights) {
 86         _columnHeights = [NSMutableArray array];
 87     }
 88     return _columnHeights;
 89 }
 90 
 91 - (NSMutableArray *)attrsArray
 92 {
 93     if (!_attrsArray) {
 94         _attrsArray = [NSMutableArray array];
 95     }
 96     return _attrsArray;
 97 }
 98 
 99 /**
100  * 初始化
101  */
102 - (void)prepareLayout
103 {
104     [super prepareLayout];
105     
106     self.contentHeight = 0;
107     
108     // 清除以前计算的所有高度
109     [self.columnHeights removeAllObjects];
110     for (NSInteger i = 0; i < self.columnCount; i++) {
111         [self.columnHeights addObject:@(self.edgeInsets.top)];
112     }
113     
114     // 清除之前所有的布局属性
115     [self.attrsArray removeAllObjects];
116     // 开始创建每一个cell对应的布局属性
117     NSInteger count = [self.collectionView numberOfItemsInSection:0];
118     for (NSInteger i = 0; i < count; i++) {
119         // 创建位置
120         NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
121         // 获取indexPath位置cell对应的布局属性
122         UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:indexPath];
123         [self.attrsArray addObject:attrs];
124     }
125 }
126 
127 /**
128  * 决定cell的排布
129  */
130 - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
131 {
132     return self.attrsArray;
133 }
134 
135 /**
136  * 返回indexPath位置cell对应的布局属性
137  */
138 - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
139 {
140     // 创建布局属性
141     UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
142     
143     // collectionView的宽度
144     CGFloat collectionViewW = self.collectionView.frame.size.width;
145     
146     // 设置布局属性的frame
147     CGFloat w = (collectionViewW - self.edgeInsets.left - self.edgeInsets.right - (self.columnCount - 1) * self.columnMargin) / self.columnCount;
148     CGFloat h = [self.delegate waterflowLayout:self heightForItemAtIndex:indexPath.item itemWidth:w];
149     
150     // 找出高度最短的那一列
151     NSInteger destColumn = 0;
152     CGFloat minColumnHeight = [self.columnHeights[0] doubleValue];
153     for (NSInteger i = 1; i < self.columnCount; i++) {
154         // 取得第i列的高度
155         CGFloat columnHeight = [self.columnHeights[i] doubleValue];
156         
157         if (minColumnHeight > columnHeight) {
158             minColumnHeight = columnHeight;
159             destColumn = i;
160         }
161     }
162     
163     CGFloat x = self.edgeInsets.left + destColumn * (w + self.columnMargin);
164     CGFloat y = minColumnHeight;
165     if (y != self.edgeInsets.top) {
166         y += self.rowMargin;
167     }
168     attrs.frame = CGRectMake(x, y, w, h);
169     
170     // 更新最短那列的高度
171     self.columnHeights[destColumn] = @(CGRectGetMaxY(attrs.frame));
172     
173     // 记录内容的高度
174     CGFloat columnHeight = [self.columnHeights[destColumn] doubleValue];
175     if (self.contentHeight < columnHeight) {
176         self.contentHeight = columnHeight;
177     }
178     return attrs;
179 }
180 
181 - (CGSize)collectionViewContentSize
182 {
183     //    CGFloat maxColumnHeight = [self.columnHeights[0] doubleValue];
184     //    for (NSInteger i = 1; i < self.columnCount; i++) {
185     //        // 取得第i列的高度
186     //        CGFloat columnHeight = [self.columnHeights[i] doubleValue];
187     //
188     //        if (maxColumnHeight < columnHeight) {
189     //            maxColumnHeight = columnHeight;
190     //        }
191     //    }
192     return CGSizeMake(0, self.contentHeight + self.edgeInsets.bottom);
193 }
194 
195 @end

设计的思想源于tableView, 每个item的高度不该由控件本身决定,而是应该由数据决定, 通过代理告诉我每个item返回多高,边界距离, 如果没有实现代理方法,那么返回默认宽高,边界距离, 不依赖于任何数据模型

9 - 瀑布流 - 这才是实现"瀑布流"效果最行之有效的办法

标签:

原文地址:http://www.cnblogs.com/chnyang/p/5447945.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!