您的位置:首页 > 产品设计 > UI/UE

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

2015-07-25 22:47 465 查看
这里的瀑布流有两种写法,第一种是继承了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需要把这两个也考虑上
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: