在开发时,看到CollectionView制作的瀑布流图册很好看,于是就做了一个,效果确实可以。刚好在开发时有这种布局需求,于是把之前做的瀑布流拿来改进,还是遇到了许多问题。
先看一下效果,
首先是,需求加了个头视图在顶部,在collectionView中的头视图跟TableView的不一样,TableView只要设置
tableview.tableHeaderView就可以了,而collectionView需要在代理中设置头,尾视图。
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
UICollectionReusableView *reusableView =nil;
if (kind ==UICollectionElementKindSectionHeader) {
UICollectionReusableView *header = [collectionViewdequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeaderwithReuseIdentifier:@"HeaderView"forIndexPath:indexPath];
reusableView = header;
}
reusableView.backgroundColor = [UIColorgreenColor];
if (kind ==UICollectionElementKindSectionFooter)
{
UICollectionReusableView *footerview = [collectionViewdequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooterwithReuseIdentifier:@"FooterView"forIndexPath:indexPath];
footerview.backgroundColor = [UIColorpurpleColor];
reusableView = footerview;
}
return reusableView;
}
但是你会发现,使用瀑布流的时候,UICollectionViewFlowLayout是自定义的布局,collectionView的代理不会走,在网上搜了很多也没有什么解决方法,都是一个版本的复制粘贴使用这种代理方法来设置的,因为他们没用使用自定义的瀑布流布局,Cell都是相同大小的布局,所以,这里就比较坑了。
最后在CocoChina的一个论坛搜到一个说加HeaderView的,看了一下,就是在自定义的Layout中添加加一个 Header类型的 UICollectionViewLayoutAttributes就可以。然后我把瀑布流的Cell的起始位置从headerView的最大Y开始布局。这样设置之后,controllerView中的代理方法才会走,要记得注册头视图哦,不然会崩。
然后还有一个问题就是,瀑布流自定义布局,这个网上很多,不懂的自己搜,我也是照网上的做,一开始内容都是图片,只要在自定义的Layout中根据当前cell的图片设置该cell的布局大小就行。方法也是先走的layout中的设置方法,再走CollectionView的代理方法,所以这里就比较坑了,要先把每个cell的大小根据内容计算出来给layout布局设置,再去代理方法中设置自定义的Cell的内容。一开始内容是一张图片还好,只要每次取出来计算image.size就可以了,而需求是自定义的cell中有图片,文字的一些内容,所以只能专门写一个计算cell宽高的类。网上有人写了个缓存这个宽高值的类,我就没有去做了。我贴一下关键的代码吧。
自定义的瀑布流布局Layout中,添加头和cell的Attribute,
- (void)prepareLayout
{
[superprepareLayout];
CGFloat screenW =CGRectGetWidth([UIScreenmainScreen].bounds);
// 重置每一列的最大Y值
[self.columnMaxYArrayremoveAllObjects];
for (int i =0; i < self.columnCount; i ++) {
[self.columnMaxYArrayaddObject:@(self.sectionEdge.top)];
}
//计算所有cell的布局属性
[self.attributeArrayremoveAllObjects];
//头部视图
UICollectionViewLayoutAttributes * layoutHeader = [UICollectionViewLayoutAttributeslayoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeaderwithIndexPath:[NSIndexPathindexPathWithIndex:0]];
layoutHeader.frame =CGRectMake(0,0, screenW, self.sectionEdge.top);
[self.attributeArrayaddObject:layoutHeader];
//item内容视图
NSInteger count = [self.collectionViewnumberOfItemsInSection:0];
for (int i =0; i < count; i ++) {
UICollectionViewLayoutAttributes * attribute = [selflayoutAttributesForItemAtIndexPath:[NSIndexPathindexPathForRow:i inSection:0]];
[self.attributeArrayaddObject:attribute];
}
}
controllerView中要注册Cell和头,这里的cell和头都是自定义的,
[_communityCollectionViewregisterClass:[CommunityCollectionViewCellclass]forCellWithReuseIdentifier:@"CollectionCell"];
[_communityCollectionViewregisterClass:[CommunityHeaderViewclass] forSupplementaryViewOfKind:UICollectionElementKindSectionHeaderwithReuseIdentifier:@"HeaderView"];
在拿到请求数据的地方调用该方法为自定义的瀑布流Layout设置高度回调,里面的方法是根据数据内容来计算布局高度的,这个根据自己的内容来计算。
#pragma mark - 计算Item高度回调
- (void)counterItemHightByCommunityDataArray:(NSArray *)dataArray
{
_communityLayout.itemHightBlock = ^CGFloat (NSIndexPath * index,CGFloat width){
CGFloat itemH = [cellHCountercountCellHightByCommunityData:communityDataArray[index.item]];
return itemH;
};
}
然后collectionView的Heard头视图设置代理就可以走了,设置一下自定义的头视图,
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
UICollectionReusableView * reusableview =nil;
if (kind ==UICollectionElementKindSectionHeader){
_heardView = [collectionViewdequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeaderwithReuseIdentifier:@"HeaderView"forIndexPath:indexPath];
reusableview = _heardView;
}
return reusableview;
}
好了,关键的代码就这些了。