iOS流布局UICollectionView系列四——自定义FlowLayout进行瀑布流布局

iOS流布局UICollectionView系列四——自定义FlowLayout进行瀑布流布局

一、引言

        前几篇博客从UICollectionView的基础应用到设置UICollectionViewFlowLayout更加灵活的进行布局,但都限制在系统为我们准备好的布局框架中,还是有一些局限性,例如,如果我要进行瀑布流似的不定高布局,前面的方法就很难满足我们的需求了,如下:

这种布局无疑在app的应用中更加广泛,商品的展示,书架书目的展示,都会倾向于采用这样的布局方式,当然,通过自定义FlowLayout,我们也很容易实现。

二、进行自定义瀑布流布局

        首先,我们新建一个文件继承于UICollectionViewFlowLayout:

?


1

@interface MyLayout : UICollectionViewFlowLayout

为了演示的方面,这里我不错更多的封装,添加一个属性,直接让外界将item个数传递进来,我们把重心方法重写布局的方法上:

?


1

2

3

@interface MyLayout : UICollectionViewFlowLayout

@property(nonatomic,assign)int itemCount;

@end

前面说过,UICollectionViewFlowLayout是一个专门用来管理collectionView布局的类,因此,collectionView在进行UI布局前,会通过这个类的对象获取相关的布局信息,FlowLayout类将这些布局信息全部存放在了一个数组中,数组中是UICollectionViewLayoutAttributes类,这个类是对item布局的具体设置,以后咱们在讨论这个类。总之,FlowLayout类将每个item的位置等布局信息放在一个数组中,在collectionView布局时,会调用FlowLayout类layoutAttributesForElementsInRect:方法来获取这个布局配置数组。因此,我们需要重写这个方法,返回我们自定义的配置数组,另外,FlowLayout类在进行布局之前,会调用prepareLayout方法,所以我们可以重写这个方法,在里面对我们的自定义配置数据进行一些设置。

简单来说,自定义一个FlowLayout布局类就是两个步骤:

1、设计好我们的布局配置数据 prepareLayout方法中

2、返回我们的配置数组 layoutAttributesForElementsInRect方法中

示例代码如下:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

@implementation MyLayout

{

    //这个数组就是我们自定义的布局配置数组

    NSMutableArray * _attributeAttay;

}

//数组的相关设置在这个方法中

//布局前的准备会调用这个方法

-(void)prepareLayout{

    _attributeAttay = [[NSMutableArray alloc]init];

    [super prepareLayout];

    //演示方便 我们设置为静态的2列

    //计算每一个item的宽度

    float WIDTH = ([UIScreen mainScreen].bounds.size.width-self.sectionInset.left-self.sectionInset.right-self.minimumInteritemSpacing)/2;

    //定义数组保存每一列的高度

    //这个数组的主要作用是保存每一列的总高度,这样在布局时,我们可以始终将下一个Item放在最短的列下面

    CGFloat colHight[2]={self.sectionInset.top,self.sectionInset.bottom};

    //itemCount是外界传进来的item的个数 遍历来设置每一个item的布局

    for (int i=0; i<_itemCount; i++) {

        //设置每个item的位置等相关属性

        NSIndexPath *index = [NSIndexPath indexPathForItem:i inSection:0];

        //创建一个布局属性类,通过indexPath来创建

        UICollectionViewLayoutAttributes * attris = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:index];

        //随机一个高度 在40——190之间

        CGFloat hight = arc4random()%150+40;

        //哪一列高度小 则放到那一列下面

        //标记最短的列

        int width=0;

        if (colHight[0]<colHight[1]) {

            //将新的item高度加入到短的一列

            colHight[0] = colHight[0]+hight+self.minimumLineSpacing;

            width=0;

        }else{

            colHight[1] = colHight[1]+hight+self.minimumLineSpacing;

            width=1;

        }

         

        //设置item的位置

        attris.frame = CGRectMake(self.sectionInset.left+(self.minimumInteritemSpacing+WIDTH)*width, colHight[width]-hight-self.minimumLineSpacing, WIDTH, hight);

        [_attributeAttay addObject:attris];

    }

     

    //设置itemSize来确保滑动范围的正确 这里是通过将所有的item高度平均化,计算出来的(以最高的列位标准)

    if (colHight[0]>colHight[1]) {

        self.itemSize = CGSizeMake(WIDTH, (colHight[0]-self.sectionInset.top)*2/_itemCount-self.minimumLineSpacing);

    }else{

          self.itemSize = CGSizeMake(WIDTH, (colHight[1]-self.sectionInset.top)*2/_itemCount-self.minimumLineSpacing);

    }

     

}

//这个方法中返回我们的布局数组

-(NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{

    return _attributeAttay;

}

 

 

@end

自定义完成FlowLayout后,我们在ViewController中进行使用:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

- (void)viewDidLoad {

    [super viewDidLoad];

    // Do any additional setup after loading the view, typically from a nib.

    MyLayout * layout = [[MyLayout alloc]init];

    layout.scrollDirection = UICollectionViewScrollDirectionVertical;

    layout.itemCount=100;

     UICollectionView * collect  = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, 320, 400) collectionViewLayout:layout];

    collect.delegate=self;

    collect.dataSource=self;

     

    [collect registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cellid"];

   

    [self.view addSubview:collect];

     

     

}

 

 

 

-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{

    return 1;

}

-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{

    return 100;

}

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{

    UICollectionViewCell * cell  = [collectionView dequeueReusableCellWithReuseIdentifier:@"cellid" forIndexPath:indexPath];

    cell.backgroundColor = [UIColor colorWithRed:arc4random()%255/255.0 green:arc4random()%255/255.0 blue:arc4random()%255/255.0 alpha:1];

    return cell;

}

运行效果就是我们引言中的截图。

三、UICollectionViewLayoutAttributes类中我们可以配置的属性

        通过上面的例子,我们可以了解,collectionView的item布局其实是LayoutAttributes类具体配置的,这个类可以配置的布局属性不止是frame这么简单,其中还有许多属性:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

//配置item的布局位置

@property (nonatomic) CGRect frame;

//配置item的中心

@property (nonatomic) CGPoint center;

//配置item的尺寸

@property (nonatomic) CGSize size;

//配置item的3D效果

@property (nonatomic) CATransform3D transform3D;

//配置item的bounds

@property (nonatomic) CGRect bounds NS_AVAILABLE_IOS(7_0);

//配置item的旋转

@property (nonatomic) CGAffineTransform transform NS_AVAILABLE_IOS(7_0);

//配置item的alpha

@property (nonatomic) CGFloat alpha;

//配置item的z坐标

@property (nonatomic) NSInteger zIndex; // default is 0

//配置item的隐藏

@property (nonatomic, getter=isHidden) BOOL hidden; 

//item的indexpath

@property (nonatomic, strong) NSIndexPath *indexPath;

//获取item的类型

@property (nonatomic, readonly) UICollectionElementCategory representedElementCategory;

@property (nonatomic, readonly, nullable) NSString *representedElementKind; 

 

//一些创建方法

+ (instancetype)layoutAttributesForCellWithIndexPath:(NSIndexPath *)indexPath;

+ (instancetype)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind withIndexPath:(NSIndexPath *)indexPath;

+ (instancetype)layoutAttributesForDecorationViewOfKind:(NSString *)decorationViewKind withIndexPath:(NSIndexPath *)indexPath;

通过上面的属性,可以布局出各式各样的炫酷效果,正如一句话:没有做不到,只有想不到。

时间: 2024-08-30 21:15:12

iOS流布局UICollectionView系列四——自定义FlowLayout进行瀑布流布局的相关文章

iOS流布局UICollectionView系列三——使用FlowLayout进行更灵活布局

iOS流布局UICollectionView系列三--使用FlowLayout进行更灵活布局 一.引言         前面的博客介绍了UICollectionView的相关方法和其协议中的方法,但对布局的管理类UICollectionViewFlowLayout没有着重探讨,这篇博客介绍关于布局的相关设置和属性方法. UICollectionView的简单使用:http://my.oschina.net/u/2340880/blog/522613    UICollectionView相关协议

iOS流布局UICollectionView系列六——将布局从平面应用到空间

iOS流布局UICollectionView系列六--将布局从平面应用到空间 一.引言         前面,我们将布局由线性的瀑布流布局扩展到了圆环布局,这使我们使用UICollectionView的布局思路大大迈进了一步,这次,我们玩的更加炫一些,想办法将布局应用的空间,你是否还记得,在管理布局的item的具体属性的类UICollectionViewLayoutAttributrs类中,有transform3D这个属性,通过这个属性的设置,我们真的可以在空间的坐标系中进行布局设计.iOS系统

iOS流布局UICollectionView系列五——圆环布局的实现

iOS流布局UICollectionView系列五--圆环布局的实现 一.引言         前边的几篇博客,我们了解了UICollectionView的基本用法以及一些扩展,在不定高的瀑布流布局中,我们发现,可以通过设置具体的布局属性类UICollectionViewLayoutAttributes来设置设置每个item的具体位置,我们可以再扩展一下,如果位置我们可以自由控制,那个布局我们也可以更加灵活,就比如创建一个如下的circleLayout: 这种布局方式在apple的官方文档中也有

iOS流布局UICollectionView系列一——初识与简单使用UICollectionView

iOS流布局UICollectionView系列一--初识与简单使用UICollectionView 一.简介         UICollectionView是iOS6之后引入的一个新的UI控件,它和UITableView有着诸多的相似之处,其中许多代理方法都十分类似.简单来说,UICollectionView是比UITbleView更加强大的一个UI控件,有如下几个方面: 1.支持水平和垂直两种方向的布局 2.通过layout配置方式进行布局 3.类似于TableView中的cell特性外,

iOS流布局UICollectionView系列二——UICollectionView的代理方法

iOS流布局UICollectionView系列二--UICollectionView的代理方法 一.引言         在上一篇博客中,介绍了最基本的UICollectionView的使用和其中我们常用的属性和方法,也介绍了瀑布流布局的过程与思路,这篇博客是上一篇的补充,来讨论关于UICollectionView的代理方法的使用.博客地址: UICollectionView的简介和简单使用:http://my.oschina.net/u/2340880/blog/522613 二.UICol

iOS开发UINavigation系列四——导航控制器UINavigationController

iOS开发UINavigation系列四--导航控制器UINavigationController 一.引言         在前面的博客中,我么你介绍了UINavigationBar,UINavigationItem和UIToolBar,UINavigationController是将这些控件和UIViewController紧密的结合了起来,使用导航,我们的应用程序层次会更加分明,对controller的管理也更加方便.前几篇博客地址如下: UINavigationBar:http://my

默认-masonry+infinitescroll瀑布流布局怎么传参?

问题描述 masonry+infinitescroll瀑布流布局怎么传参? masonry+infinitescroll瀑布流布局怎么传参? 链接的选择器是: <div id="navigation"><a href="page?page=1"></a></div> 这里有个问题,如果<a>标签的href属性传参,例如href="page?page=1&XX=1&..."

iOS中CoreData数据管理系列四——进行数据与页面的绑定

iOS中CoreData数据管理系列四--进行数据与页面的绑定 一.引言     在上一篇博客中,我们讨论了CoreData框架中添加与查询数据的操作,事实上,在大多数情况下,这些数据都是由一个UITableView表视图进行展示的,因此,CoreData框架中还未开发者提供了一个类NSFetchedResultsController,这个类作为桥接,将视图与数据进行绑定. 添加与查询数据操作:http://my.oschina.net/u/2340880/blog/611430. 二.进行数据

iOS开发UINavigation系列二——UINavigationItem

iOS开发UINavigation系列二--UINavigationItem 一.引言         UINavigationItem是导航栏上用于管理导航项的类,在上一篇博客中,我们知道导航栏是通过push与pop的堆栈操作来对item进行管理的,同样,每一个Item自身也有许多属性可供我们进行自定制.这篇博客,主要讨论UINavigationItem的使用方法. UINavigationBar:http://my.oschina.net/u/2340880/blog/527706. 二.来