瀑布流分别用UIScrollView和UICollectionView的两种写法

来源:互联网 发布:mysql dmg for mac 编辑:程序博客网 时间:2024/05/29 13:42
这里的瀑布流有两种写法,第一种是继承了UIScrollView,自定义成类似于UITableView一样,包括数据源和代理(dataSource和delegate)
详细完美注释代码:https://github.com/xiubin2012/WaterView.git

分别需要遵守的协议:


#pragma mark 数据源协议
@protocol ScrollWaterViewDataSource <NSObject>
@required
/**  共有多少个 cell */
- (NSUInteger)numberOfWaterViewCellInWaterView:(ScrollWaterView *)waterView;


/** 返回在index位置的cell */
- (ScrollWaterViewCell *)waterView:(ScrollWaterView *)waterView cellAtIndex:(NSUInteger)index;
@end


#pragma mark 代理协议
@protocol ScrollWaterViewDelegate <UIScrollViewDelegate>
@optional


/** 返回index位置cell的高度 */
- (CGFloat)waterView:(ScrollWaterView *)waterView highAtIndex:(NSUInteger)index;


/**  返回cell的列数 */
- (CGFloat)columnOfWaterView:(ScrollWaterView *)waterView;


/** 返回选中cell的index */
- (NSUInteger)waterView:(ScrollWaterView *)waterView didSelectCellAtIndex:(NSUInteger)index;


/** 返回waterView的各种边距 */
- (CGFloat)waterView:(ScrollWaterView *)waterView marginForType:(WaterViewMarginType)type;
@end


看着这些是不是有一种UITableView的感觉?


当有了这些协议的方法以后,就知道了要显示多少个cell,以及每个cell的宽高,所以在自定义的类中要实现的就是计算cell的位置(x 和 y值)
当每次在控制器中刷新数据(reloadData)时,都需要重新计算一下所有cell的frame,所以可以把 计算cell的代码放到reloadData方法里面


唯一要注意的一点是需要自己写一个cell复用的缓存池
/**
 *  cell缓存池
 */
@property (nonatomic,strong) NSMutableSet *reUseCellSet;
// 此处省略懒加载


当cell从屏幕上消失时,需要做
[cell removeFromSuperview];
[self.reUseCellSet addObject:cell];


- (id)dequeueReusableCellWithIdentifier:(NSString *)identifier{
    __block ScrollWaterViewCell *cell = nil;
    [self.reUseCellSet enumerateObjectsUsingBlock:^(ScrollWaterViewCell *obj, BOOL *stop) {
        if ([obj.identifier isEqualToString:identifier]) {
            cell = obj;
            *stop = YES;
        }
    }];
    if (cell) {
        [self.reUseCellSet removeObject:cell];
    }
    return cell;
}






第二种方法是自定义一个UICollectionView的布局 继承自UICollectionViewLayout
属性有:
/** defaul is 10 10 10 10 */
@property (nonatomic,assign) UIEdgeInsets collectionEdgeinsets;
/** defaul is 10 */
@property (nonatomic,assign) CGFloat cloumnMargin;
/** defaul is 10 */
@property (nonatomic,assign) CGFloat rowMargin;


/** defaul is 3 */
@property (nonatomic,assign) NSUInteger cloumnsCount;


@property (nonatomic,assign) id<CollecttionWaterViewLayoutDelegate> delegate;




同样是当有了各种边距及瀑布流的列数以外,再向delegate索要cell的高度之后,唯一需要做的就是计算每个cell应该在哪个位置
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(nonnull NSIndexPath *)indexPath{
    
    __block NSString *minYofCloumn = @"0";
    [self.minYDict enumerateKeysAndObjectsUsingBlock:^(NSString  *cloumn, NSNumber *obj, BOOL * __nonnull stop) {
        if ([self.minYDict[minYofCloumn]floatValue] > [self.minYDict[cloumn]floatValue]) {
            minYofCloumn = cloumn;
        }
    }];
    float w = (self.collectionView.frame.size.width - self.collectionEdgeinsets.left - self.collectionEdgeinsets.right - (self.cloumnsCount-1)*self.cloumnMargin) / self.cloumnsCount;
    
    float h = [self.delegate WaterViewLayout:self cellHighForWidth:w atIndexPath:indexPath];
    
    float x = [minYofCloumn floatValue] * (self.cloumnMargin + w) + self.collectionEdgeinsets.left;
    
    float y = [self.minYDict[minYofCloumn] floatValue] + self.rowMargin;
    
    self.minYDict[minYofCloumn] = @([self.minYDict[minYofCloumn] floatValue] + h + self.rowMargin);
    
    UICollectionViewLayoutAttributes *attri = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    attri.frame = CGRectMake(x, y, w, h);
    
    return attri;
}
这种方法较之上面一种更为简单因为除了计算cell的x和y值之外,不需要考虑缓存池和判断cell是否在屏幕上


最后两种方法都需要考虑的是代理中有没有导航控制器或者UITabBarController,因为contenSize需要把这两个也考虑上
0 0
原创粉丝点击