今天讲讲大名鼎鼎的瀑布流,说实话这个已经很久了但是才想起把它写出来,先来个效果图看下吧....
前方高能!!! 注意!!!
不是让你们看胸的,切记......
模块化了一下瀑布流类,好吧上代码....
这是在外部调用它,是不是很方便,简简单单4行代码搞定.... 好了讲完了....
(好吧... 本来准备空白下一篇才展示出来但是不知道markDown怎么实现... 苦逼....)
你以为你李哥是这么不靠谱个人么?这就完了?这我出门不得挨揍啊....
这是封装好了留给外部调用的有几个参数是我们这边要用的 代码看下应该都能知道是做什么的..继续看实现部分...
- (instancetype)initWithFrame:(CGRect)frame ownerController:(UIViewController *)viewcontroller supView:(UIView *)supView
{
self = [super init];
if (self) {
[JWEvent defaultJWEvent].hobbyGalleryTimesOfOnce = 0;
[JWEvent defaultJWEvent].tattooGalleryTimesOfOnce = 0;
loadBackImgColor = [NSArray arrayWithObjects:@(0x8c946b),@(0xf2e6bc),@(0xa56452),@(0xc2c2c2),@(0x837467),@(0xe5bbbc),@(0xcbb7a6),@(0xbddecd),@(0xffffff),@(0x000f05),@(0x637b7b),@(0x7c201f), nil];
_superVc = viewcontroller;
_dataListArray = [[NSMutableArray alloc]init];
layout = [[JWWaterLayout alloc]init];
_parm = [[NSMutableDictionary alloc]init];
[_parm setObject:@(20) forKey:@"limit"];
_listCollection = [[UICollectionView alloc]initWithFrame:frame collectionViewLayout:layout];
[_listCollection registerClass:[WaterFallHeader class] forSupplementaryViewOfKind:WaterFallSectionHeader withReuseIdentifier:@"WaterFallSectionHeader"];
[_listCollection registerClass:[JWCollectionViewCell class] forCellWithReuseIdentifier:@"squareListcell"];
_listCollection.dataSource = self;
_listCollection.delegate = self;
_listCollection.backgroundColor = [UIColor whiteColor];
[supView addSubview:_listCollection];
currentUpdated = nil;
self.backImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 120, 160)];
self.backImage.contentMode = UIViewContentModeCenter;
self.backImage.centerX = SCREENWIDTH * 0.5;
self.backImage.centerY = SCREENHEIGHT * 0.5;
self.backImage.image = [UIImage imageNamed:@"img_no_content"];
_listCollection.backgroundView = self.backImage;
}
return self;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return _dataListArray.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString* identifier = @"squareListcell";
JWCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
JWCollectionItem *item = _dataListArray[indexPath.row];
if (item) {
[cell setDataItem:_dataListArray[indexPath.row] withColor:RGBCOLOR_HEX(0xeeeeee)];
}
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
JWCollectionItem *item = [_dataListArray objectAtIndex:indexPath.row];
return item.squareListSize;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
if ([[User defaultUser].item.sector integerValue] == 30) {
[JWEvent defaultJWEvent].tattooGalleryTimesOfOnce++;
}else{
[JWEvent defaultJWEvent].hobbyGalleryTimesOfOnce++;
}
if ([collectionView isHeaderRefreshing] || [collectionView isFooterRefreshing])return;
JWCollectionItem *item = (JWCollectionItem *)[_dataListArray objectAtIndex:indexPath.row];
if (!item._id || !_superVc) {
return;
}
ImageFeedInfoDetailViewController *detailVC = [[ImageFeedInfoDetailViewController alloc]initWithQuery:@{@"feedId":item._id}];
detailVC.isTuKuPush = YES;
[_superVc.navigationController pushViewController:detailVC animated:YES];
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout heightForHeaderInSection:(NSInteger)section
{
if (_headView) {
return _headView.height;
}
return 0;
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
UICollectionReusableView *reusableView = nil;
if ([kind isEqualToString:WaterFallSectionHeader] && _headView)
{
reusableView = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"WaterFallSectionHeader" forIndexPath:indexPath];
WaterFallHeader* header = [[WaterFallHeader alloc]initWithFrame:CGRectMake(0, 0, SCREENWIDTH, _headView.height) withSubView:_headView];
[reusableView addSubview:header];
return reusableView;
}
return nil;
}
其实这些都没什么的,瀑布流主要是Layout计算高度 所以我重写了Layout..
#pragma mark - Methods to Override
- (void)prepareLayout
{
[super prepareLayout];
NSInteger numberOfSections = [self.collectionView numberOfSections];
if (numberOfSections == 0)
{
return;
}
self.delegate = (id <JWWaterLayoutDelegate> )self.collectionView.delegate;
NSInteger idx = 0;
CGFloat width = self.collectionView.frame.size.width - self.sectionInset.left - self.sectionInset.right;
self.itemWidth = floorf((width - (self.columnCount - 1) * self.minimumColumnSpacing) / self.columnCount);
[self.headersAttribute removeAllObjects];
[self.footersAttrubite removeAllObjects];
[self.unionRects removeAllObjects];
[self.columnHeights removeAllObjects];
[self.allItemAttributes removeAllObjects];
if (self.sectionItemAttributes) {
[self.sectionItemAttributes removeAllObjects];
}
for (idx = 0; idx < self.columnCount; idx++)
{
[self.columnHeights addObject:@(0)];
}
// Create attributes
CGFloat top = 0;
UICollectionViewLayoutAttributes *attributes;
for (NSInteger section = 0; section < numberOfSections; ++section)
{
/*
* 1. Section header
*/
CGFloat headerHeight;
if ([self.delegate respondsToSelector:@selector(collectionView:layout:heightForHeaderInSection:)])
{
headerHeight = [self.delegate collectionView:self.collectionView layout:self heightForHeaderInSection:section];
}
else
{
headerHeight = self.headerHeight;
}
if (headerHeight > 0)
{
attributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:WaterFallSectionHeader withIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
attributes.frame = CGRectMake(0, top, self.collectionView.frame.size.width, headerHeight);
self.headersAttribute[@(section)] = attributes;
[self.allItemAttributes addObject:attributes];
top = CGRectGetMaxY(attributes.frame);
}
top += self.sectionInset.top;
for (idx = 0; idx < self.columnCount; idx++)
{
self.columnHeights[idx] = @(top);
}
/*
* 2. Section items
*/
NSInteger itemCount = [self.collectionView numberOfItemsInSection:section];
NSMutableArray *itemAttributes = [NSMutableArray arrayWithCapacity:itemCount];
// Item will be put into shortest column.
for (idx = 0; idx < itemCount; idx++)
{
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:idx inSection:section];
CGSize itemSize = [self.delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath];
// CGFloat itemHeight = floorf(itemSize.height * self.itemWidth / itemSize.width);
CGFloat itemHeight = itemSize.height;
NSUInteger columnIndex = [self shortestColumnIndex];
CGFloat xOffset = self.sectionInset.left + (self.itemWidth + self.minimumColumnSpacing) * columnIndex;
CGFloat yOffset = [self.columnHeights[columnIndex] floatValue];
attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attributes.frame = CGRectMake(xOffset, yOffset, self.itemWidth, itemHeight);
[itemAttributes addObject:attributes];
[self.allItemAttributes addObject:attributes];
self.columnHeights[columnIndex] = @(CGRectGetMaxY(attributes.frame) + self.minimumInteritemSpacing);
}
[self.sectionItemAttributes addObject:itemAttributes];
/*
* Section footer
*/
CGFloat footerHeight;
NSUInteger columnIndex = [self longestColumnIndex];
top = [self.columnHeights[columnIndex] floatValue] - self.minimumInteritemSpacing + self.sectionInset.bottom;
if ([self.delegate respondsToSelector:@selector(collectionView:layout:heightForFooterInSection:)])
{
footerHeight = [self.delegate collectionView:self.collectionView layout:self heightForFooterInSection:section];
}
else
{
footerHeight = self.footerHeight;
}
if (footerHeight > 0)
{
attributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:WaterFallSectionFooter withIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
attributes.frame = CGRectMake(0, top, self.collectionView.frame.size.width, footerHeight);
self.footersAttrubite[@(section)] = attributes;
[self.allItemAttributes addObject:attributes];
top = CGRectGetMaxY(attributes.frame);
}
for (idx = 0; idx < self.columnCount; idx++)
{
self.columnHeights[idx] = @(top);
}
} // end of for (NSInteger section = 0; section < numberOfSections; ++section)
// Build union rects
idx = 0;
NSInteger itemCounts = [self.allItemAttributes count];
while (idx < itemCounts)
{
CGRect rect1 = ((UICollectionViewLayoutAttributes *)self.allItemAttributes[idx]).frame;
idx = MIN(idx + unionSize, itemCounts) - 1;
CGRect rect2 = ((UICollectionViewLayoutAttributes *)self.allItemAttributes[idx]).frame;
[self.unionRects addObject:[NSValue valueWithCGRect:CGRectUnion(rect1, rect2)]];
idx++;
}
}
- (CGSize)collectionViewContentSize
{
NSInteger numberOfSections = [self.collectionView numberOfSections];
if (numberOfSections == 0)
{
return CGSizeZero;
}
CGSize contentSize = self.collectionView.bounds.size;
contentSize.height = [self.columnHeights[0] floatValue];
return contentSize;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path
{
if (path.section >= [self.sectionItemAttributes count])
{
return nil;
}
if (path.item >= [self.sectionItemAttributes[path.section] count])
{
return nil;
}
return (self.sectionItemAttributes[path.section])[path.item];
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes *attribute = nil;
if ([kind isEqualToString:WaterFallSectionHeader])
{
attribute = self.headersAttribute[@(indexPath.section)];
} else if ([kind isEqualToString:WaterFallSectionFooter])
{
attribute = self.footersAttrubite[@(indexPath.section)];
}
return attribute;
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSInteger i;
NSInteger begin = 0, end = self.unionRects.count;
NSMutableArray *attrs = [NSMutableArray array];
for (i = 0; i < self.unionRects.count; i++)
{
if (CGRectIntersectsRect(rect, [self.unionRects[i] CGRectValue]))
{
begin = i * unionSize;
break;
}
}
for (i = self.unionRects.count - 1; i >= 0; i--)
{
if (CGRectIntersectsRect(rect, [self.unionRects[i] CGRectValue]))
{
end = MIN((i + 1) * unionSize, self.allItemAttributes.count);
break;
}
}
for (i = begin; i < end; i++)
{
UICollectionViewLayoutAttributes *attr = self.allItemAttributes[i];
if (CGRectIntersectsRect(rect, attr.frame))
{
[attrs addObject:attr];
}
}
return [NSArray arrayWithArray:attrs];
}
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{
CGRect oldBounds = self.collectionView.bounds;
if (CGRectGetWidth(newBounds) != CGRectGetWidth(oldBounds) ||
CGRectGetHeight(newBounds) != CGRectGetHeight(oldBounds))
{
return YES;
}
return NO;
}
#pragma mark - Private Methods
/**
* Find the shortest column.
*
* @return index for the shortest column
*/
- (NSUInteger)shortestColumnIndex
{
__block NSUInteger index = 0;
__block CGFloat shortestHeight = MAXFLOAT;
if (self.columnHeights) {
[self.columnHeights enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
{
if (obj) {
CGFloat height = [obj floatValue];
if (height < shortestHeight)
{
shortestHeight = height;
index = idx;
}
}
}];
}
return index;
}
/**
* Find the longest column.
*
* @return index for the longest column
*/
- (NSUInteger)longestColumnIndex
{
__block NSUInteger index = 0;
__block CGFloat longestHeight = 0;
[self.columnHeights enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
{
CGFloat height = [obj floatValue];
if (height > longestHeight)
{
longestHeight = height;
index = idx;
}
}];
return index;
}
这是计算item大小的算出最高和最矮的,代码没有全部沾出.. 但是看下流程应该都能想起该如何去实现....
代码就不附上了...