瀑布流分别用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需要把这两个也考虑上
详细完美注释代码: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需要把这两个也考虑上
相关文章推荐
- MiniGUI 消息的种类(二)
- unique Binary Tree
- PipeLine and Value
- 接收的到的Socket请求怎么转换成servletRequest
- Unique Paths
- PriorityQueue 优先级队列
- 循环数组 and ArrayDeque
- Codeforces Round #313 (Div. 2) D Equivalent Strings
- CLIQUE 聚类算法以及Java实现+多线程
- QtScript, QML, Quick1, Quick2, Declarative 之间的关系
- MiniGUI Messge (一)
- HDU4740 The Donkey of Gui Zhou 暴力模拟
- 项目文件包含 ToolsVersion="12.0" 设置,而此版本的 MSBuild 不支持该工具版本
- poj 3080 Blue Jeans
- backbone--requirejs--marionettejs--01
- HDU 5301 Buildings
- tabhost选项卡,做微信以及微博UI界面必学
- String,StringBuffer与StringBuilder的区别
- UIPanGestureRecognizer类中translationInView:方法和velocityInView:方法
- 用xib自定义UITableViewCell的注意事项——重用问题