android中UIColletionView瀑布流布局实现思路以及封装的实现

发布时间:2020-09-08 16:40:18 作者:Deft_MKJing宓珂璟
来源:脚本之家 阅读:218

瀑布流实现思路

默认两列

android中UIColletionView瀑布流布局实现思路以及封装的实现 

android中UIColletionView瀑布流布局实现思路以及封装的实现

其他案例

android中UIColletionView瀑布流布局实现思路以及封装的实现  

上面的动画切换布局也是自定义UICollectionLayout来进行布局的,简单的静态图片布局展示其实就重写几个方法就可以了

1.prepareLayout 每次重新刷新collectionView的时候会调用一次,做一些初始化的工作

2.layoutAttributesForElementsInRect 返回已经制定好之后的每个cell对应的attribute属性对象进行布局

3.layoutAttributesForItemAtIndexPath 该方法会一直调用,每次cell出来就会根据对应的indexpath来进行方法调用,因此关键布局代码就可以放置在这里进行重新计算

4.collectionViewContentSize 计算整体的大小,实现滚动

上面插入样式实现的传送门

瀑布流实现分析

1.基本变量的声明

// 每一列的间距
static const CGFloat MKJDefaultColumnMargin = 10;
// 每一行间距
static const CGFloat MKJDefaultRowMargin = 10;
// 整体的上间距,左间距,下间距,右间距
static const UIEdgeInsets MKJDefaultEdgeInsets = {10,10,10,10};
// 默认是多少列
static const NSUInteger MKJDefaultColumnCounts = 2;

@interface MKJWaterFallLayout ()

@property (nonatomic,strong) NSMutableArray *attributeArr; // cell属性的数组
@property (nonatomic,strong) NSMutableArray *columnHeightArr; // 每列的高度数组

@end

2.初始化

// 每次刷新会调用一次
- (void)prepareLayout
{
  [super prepareLayout];

  // 每次重新刷新的时候清除之前的所有高度值,默认就是UIEdg给定的top
  [self.columnHeightArr removeAllObjects];
  for (NSInteger i = 0; i < [self columnCount]; i++) {
    [self.columnHeightArr addObject:@([self insetMargin].top)];
  }
  // 每次刷新把对应的att属性清空
  [self.attributeArr removeAllObjects];
  // 初始化一次每个cell对应的attribute属性
  NSInteger count = [self.collectionView numberOfItemsInSection:0];
  for (NSInteger i = 0; i < count; i++) {
    NSIndexPath *indexpath = [NSIndexPath indexPathForItem:i inSection:0];
    UICollectionViewLayoutAttributes *attribute = [self layoutAttributesForItemAtIndexPath:indexpath];
    [self.attributeArr addObject:attribute];
  }
}

3.关键计算代码

// 返回attribute属性数组决定最后的排布
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{
  return self.attributeArr;
}

// 返回对应的indexpath下每个cell的属性 cell的出现会一直刷新该方法
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
  // 初始化布局属性---> 对应的indexpath
  UICollectionViewLayoutAttributes *att = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];

  CGFloat collectionW = self.collectionView.frame.size.width;

  // 宽度是根据列数和间距固定算出来的
  CGFloat width = (collectionW - [self insetMargin].left - [self insetMargin].right - ([self columnCount] - 1) * [self columnMargin]) / [self columnCount];

  // 高度是根据代理的数据源返回比例计算的
  CGFloat height = [self.delegate MKJWaterFallLayout:self heightForItemAtIndexPath:indexPath] * width;
  // X 和 Y值都是在找出最小column之后才能确定,核心就是根据列数,找出最小高度的那一列
  // 先取出第一个默认是最小的
  CGFloat minColumnHeight = [self.columnHeightArr[0] doubleValue];
  // 默认最小的是第0列
  NSUInteger finalCol = 0;
  for (NSInteger i = 1 ; i < [self columnCount]; i++) {
    CGFloat currentColHeight = [self.columnHeightArr[i] doubleValue];
    if (minColumnHeight > currentColHeight) {
      minColumnHeight = currentColHeight;
      finalCol = i;
    }
  }

  // x,y值是根据最小高度列算出来的
  CGFloat x = [self insetMargin].left + (width + [self columnMargin]) * finalCol;
  CGFloat y = minColumnHeight;
  // 当你是一个行排布的时候 默认是top值,不需要加间距
  NSInteger count = indexPath.item;
  if ((count / ([self columnCount])) >= 1) {
    y += [self rowMargin];
  }
  att.frame = CGRectMake(x, y, width, height);
  self.columnHeightArr[finalCol] = @(CGRectGetMaxY(att.frame));
  return att;

}

这里的计算简概括为就是对每个cell进行frame的计算

1.宽度的计算是根据列间距和整体左右间距以及行数进行限制,这些参数可以是固定值,也可以是代理传进去的

2.高度的计算必定是根据外部代理进行计算的

3.X值的计算是根据这个框架内部的每一列的高度数组进行之前的缓存高度,进行最小值计算,然后拿出最小值对应的列数,根据上面算出来的高度进行X值的计算

4.Y值的计算和X值一样,根据给定的数组,比出最小高度列的列数,根据数组的高度,计算出对应的Y值,最终再进行数组对应列数的高度更新

4.获取实际能容大小,让其可以滚动

// 计算出滚动区域的大小
- (CGSize)collectionViewContentSize
{
  CGFloat maxColumHeight = [self.columnHeightArr[0] doubleValue];
  for (NSInteger i = 1; i < [self columnCount]; i++) {
    CGFloat currentColHeight = [self.columnHeightArr[i] doubleValue];
    if (maxColumHeight < currentColHeight) {
      maxColumHeight = currentColHeight;
    }
  }
  return CGSizeMake(0, maxColumHeight + [self insetMargin].bottom);

}

5.这个小框架已经封装好了,简单介绍下用法

// 声明如下
- (UICollectionView *)colletionView
{
  if (_colletionView == nil) {
    MKJWaterFallLayout *layout = [[MKJWaterFallLayout alloc] init];
    layout.delegate = self;
    UICollectionView *collectionV = [[UICollectionView alloc] initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:layout];
    collectionV.backgroundColor = [UIColor redColor];
    [collectionV registerNib:[UINib nibWithNibName:productID bundle:nil] forCellWithReuseIdentifier:productID];
    collectionV.delegate = self;
    collectionV.dataSource = self;
    _colletionView = collectionV;

  }
  return _colletionView;
}

// 内部行数,间距的控制
#pragma mark - waterfallLayoutDelegate
- (CGFloat)MKJWaterFallLayout:(MKJWaterFallLayout *)layout heightForItemAtIndexPath:(NSIndexPath *)indexPath
{
  // 返回宽度和高度比例
  MKJProductModel *product = self.dataSource[indexPath.item];
  return product.h / product.w;
}

// 控制列间距
- (CGFloat)columnMarginForWaterFallLayout:(MKJWaterFallLayout *)collectionViewLayout
{
  return 10;
}
// 控制行间距
- (CGFloat)rowMarginForWaterFallLayout:(MKJWaterFallLayout *)collectionViewLayout
{
  return 30;
}
// 控制列数
- (NSUInteger)columnCountForWaterFallLayout:(MKJWaterFallLayout *)collectionViewLayout
{
//  if (self.dataSource.count > 50) {
//    return 3;
//  }
  return 3;
}
// 控制整体上左下右间距
- (UIEdgeInsets)insetForWaterFallLayout:(MKJWaterFallLayout *)collectionViewLayout
{
  return UIEdgeInsetsMake(10, 10, 10, 10);
}

Demo地址: http://xiazai.jb51.net/201702/yuanma/MKJWaterFallLayout_jb51.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持亿速云。

推荐阅读:
  1. 如何实现瀑布流布局
  2. Promise的实现思路是什么

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

uicollection 瀑布流 roi

上一篇:Java Web 开发中web、jsp的详细介绍

下一篇:解决pycharm不能自动补全第三方库的函数和属性问题

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》