SoulmateL / WaterFlowDemo

标注非常详细的瀑布流实现

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

LJJWaterFlowLayout

注释得非常清楚的瀑布流实现和想法

CarouselView in action

准备布局item前调用,可以在这里面完成必要属性的初始化

- (void)prepareLayout {
    [super prepareLayout];
    //初始化间距
    self.minimumInteritemSpacing = kInterItemSpacing;
    self.minimumLineSpacing = kLineSpacing;
    //初始化存储容器
    _attributes = [NSMutableDictionary dictionary];
    _cloArray = [NSMutableArray arrayWithCapacity:kColumnCount];
    for (int i=0; i<kColumnCount; ++i) {
        [_cloArray addObject:@(0.f)];
    }
    self.delegate = (id<UICollectionViewDelegateFlowLayout>)self.collectionView.delegate;
    //遍历所有item获取位置信息并且储存

    NSUInteger sectionCount = [self.collectionView numberOfSections];
    for (int section=0; section<sectionCount; ++section) {
        NSUInteger itemCount = [self.collectionView numberOfItemsInSection:section];
        for (int row=0; row<itemCount; ++row) {
            [self layoutEachItemFrameAtIndexPath:[NSIndexPath indexPathForRow:row inSection:section]];
            }
    }
}

设置每个item的尺寸并和indexPath为键值对存在字典里

- (void)layoutEachItemFrameAtIndexPath:(NSIndexPath *)indexPath {
    //代理获取itemSize
    UIEdgeInsets edgeInsets = [self.delegate collectionView:self.collectionView layout:self insetForSectionAtIndex:indexPath.section];
    CGSize itemSize = [self.delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath];
    NSLog(@"前大小:%@",NSStringFromCGSize(itemSize));

    CGFloat itemWidth = (kScreenWidth - (kColumnCount - 1)*kInterItemSpacing-edgeInsets.left-edgeInsets.right) / 3;

    CGFloat itemHeight = itemWidth*itemSize.height/itemSize.width;
    //得到等比例大小
    itemSize = CGSizeMake(itemWidth, itemHeight);
    NSLog(@"得到等比例大小:%@",NSStringFromCGSize(itemSize));
    //获取列数中高度最低的一组
    NSUInteger miniClo = 0;
    CGFloat miniHeight = [_cloArray[miniClo] floatValue];
    for (int clo=1; clo<_cloArray.count; ++clo) {
        CGFloat currentCloHeight = [_cloArray[clo] floatValue];
    //如果当前列的高度小于最低y高度,则重新赋值
        if (miniHeight > currentCloHeight) {
            miniHeight = currentCloHeight;
            miniClo = clo;
        }
    }

    //找到高度最小的列为clo,最小高度为miniClo
    //在当前高度最低的列上面追加item并且存储位置信息
    CGFloat x = edgeInsets.left + miniClo*(kInterItemSpacing+itemWidth);
    CGFloat y = edgeInsets.top + miniHeight;
    //确定cell的frame
    CGRect frame = CGRectMake(x, y, itemSize.width, itemSize.height);
    //每个cell的frame对应一个indexPath,放入字典中
    [_attributes setValue:indexPath forKey:NSStringFromCGRect(frame)];
    //更新列高
    [_cloArray replaceObjectAtIndex:miniClo withObject:@(CGRectGetMaxY(frame))];
}

返回所有当前在可视范围内的item的布局属性

- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
    //初始化可视化范围内应该显示的所有item的位置数组
    NSMutableArray *indexPaths = [NSMutableArray array];
    //遍历存放item位置信息的字典,并找到需要显示的item
    for (NSString *itemRectInfo in _attributes) {
        CGRect itemRect = CGRectFromString(itemRectInfo);
        //通过CGRectIntersectsRect方法确定每个item的rect与传入的rect是否有交集,如果有交集则说明这个item需要显示,所有我们将item的位置indexPath加入数组
        if (CGRectIntersectsRect(itemRect, rect)) {
            NSIndexPath *indexPath = _attributes[itemRectInfo];
            [indexPaths addObject:indexPath];
        }
    }

    //初始化存需要显示的item的数组
    NSMutableArray *attributeArray = [NSMutableArray arrayWithCapacity:indexPaths.count];
    for (NSIndexPath *index in indexPaths) {
        UICollectionViewLayoutAttributes *attribute = [self layoutAttributesForItemAtIndexPath:index];
        [attributeArray addObject:attribute];
    }
    return attributeArray;
}



- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    for (NSString * itemFrame in _attributes) {
        if (_attributes[itemFrame] == indexPath) {
            attribute.frame = CGRectFromString(itemFrame);
            break;
        }
    }
    return attribute;
}

计算collectionView的可滚动范围,必重写

- (CGSize)collectionViewContentSize {
    CGFloat maxHeight = [_cloArray[0] floatValue];
    for (int clo=1; clo<_cloArray.count; ++clo) {
        CGFloat currentCloHeight = [_cloArray[clo] floatValue];
        if (maxHeight < currentCloHeight) {
            maxHeight = currentCloHeight;
        }
    }
    return CGSizeMake(CGRectGetWidth(self.collectionView.frame), maxHeight + self.collectionView.contentInset.bottom);
}

About

标注非常详细的瀑布流实现


Languages

Language:Objective-C 100.0%