DEMO示例展示
- 对于瀑布流的实现是对于自定义UICollectionViewLayout进行item的自定义排布
1<在实现其中的几个必要的方法
/**
* 准备布局
*/
- (void)prepareLayout{
}
/**
* 决定cell的排布
*/
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
}
/**
* 布局item的具体位置
*/
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
}
/**
* 布局的滚动范围
*/
- (CGSize)collectionViewContentSize{
}
上述就是瀑布流布局的四个核心的方法.在其中的方法中进行布局计算item的大小跟位置放在所在相应的布局上根据每次返回的最低高度进行布局.
所以这就要求我们获取item的所在布局的那一列所在的高度,获取到item的大小X.Y的值就能获取到他的frame
/** 存到所有cell的布局 */
@property (nonatomic,strong)NSMutableArray *attsArray;
/** 存放所有列的当前高度 */
@property (nonatomic,strong)NSMutableArray *columnHeights;
- 定义了两个属性用来计算所在列的cell的最大Y值 依次遍历获取数值.
/**
* 布局item的具体位置
*/
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewLayoutAttributes *atts = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
//布局item
CGFloat collectionViewW = self.collectionView.frame.size.width;
CGFloat W = (collectionViewW - self.edgeInsets.left - self.edgeInsets.right - (self.columnCount - 1) * self.columnMargin) / self.columnCount;
//获取到collectionView的item的最短的那一列
NSUInteger destColumn = 0;
CGFloat minColumnHeight = [self.columnHeights[0] doubleValue];
for (NSUInteger i = 1; i < self.columnCount; i ++) {
//获取i行的高度
CGFloat columnHeight = [self.columnHeights[i] doubleValue];
if (minColumnHeight > columnHeight) {
minColumnHeight = columnHeight;
destColumn = i;
}
}
CGFloat X = self.edgeInsets.left + destColumn * (W + self.columnMargin);
CGFloat Y = minColumnHeight;
if (Y != self.edgeInsets.top) {
Y += self.rowMargin;
}
CGFloat H = [self.delegate waterViewLayout:self heightForItemAtIndex:indexPath.item itemWidth:W];
atts.frame = CGRectMake(X, Y, W, H);
//更新最短的高度
self.columnHeights[destColumn] = @(CGRectGetMaxY(atts.frame));
return atts;
}
- 最后是对于计算整个瀑布流的滚动范围也就是contsize的取值范围,也就是获取整个item的最大高度的范围即可
/**
* 布局的滚动范围
*/
- (CGSize)collectionViewContentSize {
CGFloat maxColumnHeight = [self.columnHeights[0] doubleValue];
for (NSUInteger i = 1; i < self.columnCount; i ++) {
//获取i行的高度
CGFloat columnHeight = [self.columnHeights[i] doubleValue];
if (columnHeight > maxColumnHeight) {
maxColumnHeight = columnHeight;
}
}
return CGSizeMake(0, maxColumnHeight + self.edgeInsets.bottom);
}
以上的就是核心的瀑布流的算法.
- 对于笔者其他的文件也没什么可以展示的,就是一些所在的数据源跟collectionView的布局. 详情可以参照demo的地址.
最后想分享的是这个瀑布流笔者封装了起来留有所在行数的间距跟所在列的接口,不需要以后每次都会重新写自定义流水布局.只许进行测试调用所在列为多少即可.
#import <UIKit/UIKit.h>
@class WKWaterViewLayout;
@protocol WKWaterViewLayoutDelegate <NSObject>
@required
/** 外部所在的尺寸计算布局内的高度 */
- (CGFloat)waterViewLayout:(WKWaterViewLayout *)waterLayout heightForItemAtIndex:(NSUInteger)index itemWidth:(CGFloat)itemWidth;
@optional
/** 瀑布流所在的列数 */
- (CGFloat)columnCountInWaterflowLayout:(WKWaterViewLayout *)waterflowLayout;
/** item的每一列的边距 */
- (CGFloat)columnMarginInWaterflowLayout:(WKWaterViewLayout *)waterflowLayout;
/** item的每一行的边距 */
- (CGFloat)rowMarginInWaterflowLayout:(WKWaterViewLayout *)waterflowLayout;
/** 内边距 */
- (UIEdgeInsets)edgeInsetsInWaterflowLayout:(WKWaterViewLayout *)waterflowLayout;
@end
@interface WKWaterViewLayout : UICollectionViewLayout
@property (nonatomic,weak)id<WKWaterViewLayoutDelegate> delegate;
@end
demo 下载地址:https://github.com/aryehToDog/WK-WaterFlowLaout/tree/master