瀑布流

瀑布流

  • 根据上一篇的UICollectionView,现在我们来搭建一个瀑布流的布局。

这个就是瀑布流布局
思路:分三列,用个数组来存放三列的最底部y值,比较哪个最小,那么下一个cell就放哪个位置

框架的思路:自己写个瀑布流的布局框架

  • 定义一些成员变量,提供给外界设置
  • 这里有四边距、水平间距、垂直间距、默认列数
@property (assign,nonatomic) CGFloat horizontalMargin;
@property (assign,nonatomic) CGFloat verticalMargin;
@property (assign,nonatomic) NSInteger columps;
@property (assign,nonatomic) UIEdgeInsets insets;
  • 如果不设置的话,我们有默认值:(注意这个不是view,没有initwithframe方法)
- (instancetype)init{
    if (self = [super init]) {
        _horizontalMargin = 10;
        _verticalMargin = 10;
        _columps = 3;
        _insets = UIEdgeInsetsMake(10, 10, 10, 10);
    }
    return self;
}

计算排布

  • 在layoutAttributesForElementsInRect方法里计算cell的排布
  • 用一个数组bottomYArray来存放各个列最大的y值,元素个数等于collectionView的列数。每次要放新的cell,就查看数组中哪个列y值最小,就放到哪列
  • 搞个数组成员属性,懒加载。初始化,给数组中添加若干个元素(等于上部内边距的值,个数等于列数)。注意要先把里面的数据移除,(不这么做的话,重新来到这个方法,高度就从之前的高度往下算了)
  • 计算数组中最小值的方法:
- (NSInteger)getShortestTag{
    // shortestTag记录是数组中第几个
    NSInteger shortestTag = 0;
    // shortestY记录最小的Y值
    CGFloat shortestY = [self.bottomYArray[0] floatValue];
    // 遍历数组,如果有更小的,那么让shortestY等于它,shortestTag等于它对应的i
    for (int i = 1; i < self.bottomYArray.count; i++) {
        if ([self.bottomYArray[i] floatValue] < shortestY ) {
            shortestY = [self.bottomYArray[i] floatValue];            
            shortestTag = i;
        }
    }
    // 返回告诉外面哪一个的Y值最小
    return shortestTag;
}
  • layoutAttributesForElementsInRect方法中计算出cell的frame,其中cell的高度暂且用个随机数,cell的y值就是数组bottomYArray中按照上面的方法计算出的位置的元素值。
  • 注意`每次计算完一个cell的frame,要用这个cell的Y值替换掉bottomYArray中的对应位置元素的值*
  • 具体计算过程和代码的演示在上一篇博客里已经写的很详细了,这里不再赘述。

计算contentSize

  • 封装一个方法计算整体最大高度,用来设置contentSize,计算方式同上面计算最小Y值一样
  • 在collectionViewContentSize方法里设置好contentSize返回
  • 结果程序崩了,告诉我们数组越界。
  • 断点排查,发现问题是程序刚启动,会先调用collectionViewContentSize方法。此时数组bottomYArray还是空的,它添加元素的代码在layoutAttributesForElementsInRect方法里。
  • 那么,我们在collectionViewContentSize方法里添加这么一段代码就可以了:如果数组是空的,那么就返回个0,0,反正开始拖动它还会来调这个方法来计算的,那时候数组已经有元素了
    if (self.bottomYArray.count == 0) {
        return CGSizeMake(0, 0);
    }

其它bug

  • 但是拖动一下会出问题:乱排了,因为方法layoutAttributesForElementsInRect在拖动了就会重新调用,重新计算布局了(具体内部计算方法不明)
  • 解决:把计算排布的代码放到- (void)preparelayout方法里,这里只会计算一次;设置成员属性来记录计算好的布局数组(懒加载),在layoutAttributesForElementsInRect方法里直接拿到布局数组返回就可以了
    • 注意要把这个布局数组也先清空,理由同上
    • preparelayout:第一次显示的时候和reloadDate的时候会调用,而且会比layoutAttributesForElementsInRect先调用

给外界提供cell的高度设置

  • 用代理:如果谁成为代理,那么可以实现代理方法给框架传递cell高度,框架内部据此来设置cell的高度
#import <UIKit/UIKit.h>
@class K2SWaterFallLayout;
@protocol K2SWaterfallLayoutDelegate <NSObject>
- (CGFloat)waterfallLayout:(K2SWaterFallLayout *)layout cellHeightWithCellWidth:(CGFloat)cellWidth atIndexPath:(NSIndexPath *)indexPath;
@end
@interface K2SWaterFallLayout : UICollectionViewLayout
@property (weak,nonatomic) id<K2SWaterfallLayoutDelegate> delegate;
  • 于是,只要外界成为代理,然后实现这个方法就能给框架传递cell的高度了
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android瀑布是一种常用于展示图片、新闻、商品等多个数据的界面布局方式。它的特点是让数据以瀑布的形式在屏幕上卡片化展示,每个卡片的高度可以不同,整体呈现出瀑布的效果。 使用Android瀑布可以在有限的屏幕空间内展示更多的内容,并且能够更好地适应不同屏幕尺寸和分辨率。它能够自动适应数据的长度和高度,使得用户观看时可以自由滑动和查看更多的内容,提升了用户的体验。 在Android中实现瀑布布局可以采用RecyclerView或GridView等布局控件,并结合Adapter来添加数据和设置布局样式。通常情况下,我们需要自定义Adapter来实现特定的布局效果,比如设置不规则的卡片高度、加载图片、设置点击事件等。 瀑布的实现方式有多种,常见的是通过计算每个卡片的高度来实现。在RecyclerView中,可以使用StaggeredGridLayoutManager来实现瀑布布局,通过设置ItemDecoration来控制卡片之间的间距。 在实际开发中,需要考虑到瀑布的性能问题,因为加载大量的图片可能会造成卡顿和内存溢出。可以采用图片加载库如Glide或Picasso来处理图片加载,并且可以使用分页加载的方式,只加载当前可见区域的数据,减少资源消耗。 总之,Android瀑布是一种能够有效展示多个数据的布局方式,可以提升用户体验,但在开发过程中需要注意性能问题,并选择合适的第三方库来处理图片加载。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值