自定义UICollectionView的布局

来源:互联网 发布:淘宝店铺运营助手工资 编辑:程序博客网 时间:2024/05/16 12:13

最近做一个项目,要实现一个用细线分割的网格,本来以为很简单,结果发现用UICollectionView自带的布局不能满足要求,不得已去研究了一下如何自定义布局。有一些收获,和大家分享一下。先看看实现的效果图:


好了,实现自定义简单的布局实际上就是将原来在UICollectionViewDataSource,UICollectionViewDelegate中的一些布局相关的方法转移到自定义布局类中去了;只需要保留几个必须的方法,这样看起来反而层次更加清晰。

1.首先定义继承UICollectionViewLayout 的子类,这里命名为FXLayout。

实现该类时有几点需要注意:

prepareLayout方法是初始化该类时调用的方法(所以不需要实现init之类的方法,记得加上[super prepareLayout]就行了),在该方法中可以初始化一些数据。我在这里初始化了单元格的数量。

苹果提供的非常方便的接口来获取当前布局类加载的UICollectionView对象,调用[self colletionView]即可。

不多说了,上代码:

//开始时执行的方法:初始化

- (void)prepareLayout

{

    [superprepareLayout];

    

    //CGSize size = self.collectionView.frame.size;

    _cellCount = [[selfcollectionView] numberOfItemsInSection:0];

}


//返回IUICollectionView所包含控件的大小:一般不会变

- (CGSize)collectionViewContentSize

{

   CGFloat sizeHeight;

   if (_cellCount%5 ==0)

    {

        sizeHeight =SCREEN_WIDTH*2/3*_cellCount/5;

    }

   else

    {

        sizeHeight =SCREEN_WIDTH*2/3*(_cellCount/5+1);

    }

   CGSize size = CGSizeMake(SCREEN_WIDTH, sizeHeight);

   return size;

}


//返回CollectionView指定单元格的大小和位置

- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath

{

    //创建返回对象

    UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributeslayoutAttributesForCellWithIndexPath:indexPath];

    //设置各个单元格的大小

   CGSize cellSize = CGSizeZero;

    CGPoint center =CGPointZero;

   if (indexPath.row%10 ==3 || indexPath.row%10 ==9)

    {

        cellSize =CGSizeMake(SCREEN_WIDTH*2/3,SCREEN_WIDTH/3);

    }

   else

    {

        cellSize =CGSizeMake(SCREEN_WIDTH/3,SCREEN_WIDTH/3);

    }

   switch (indexPath.row %10) {

       case 0:

            center =CGPointMake(SCREEN_WIDTH/6, indexPath.row/10*SCREEN_WIDTH*4/3+SCREEN_WIDTH/6);

           break;

       case 1:

            center =CGPointMake(SCREEN_WIDTH/2, indexPath.row/10*SCREEN_WIDTH*4/3+SCREEN_WIDTH/6);

           break;

       case 2:

            center =CGPointMake(SCREEN_WIDTH*5/6, indexPath.row/10*SCREEN_WIDTH*4/3+SCREEN_WIDTH/6);

           break;

       case 3:

            center =CGPointMake(SCREEN_WIDTH/3, indexPath.row/10*SCREEN_WIDTH*4/3+SCREEN_WIDTH/2);

           break;

       case 4:

            center =CGPointMake(SCREEN_WIDTH*5/6, indexPath.row/10*SCREEN_WIDTH*4/3+SCREEN_WIDTH/2);

           break;

       case 5:

            center =CGPointMake(SCREEN_WIDTH/6, indexPath.row/10*SCREEN_WIDTH*4/3+SCREEN_WIDTH*5/6);

           break;

       case 6:

            center =CGPointMake(SCREEN_WIDTH/2, indexPath.row/10*SCREEN_WIDTH*4/3+SCREEN_WIDTH*5/6);

           break;

       case 7:

            center =CGPointMake(SCREEN_WIDTH*5/6, indexPath.row/10*SCREEN_WIDTH*4/3+SCREEN_WIDTH*5/6);

           break;

       case 8:

            center =CGPointMake(SCREEN_WIDTH/6, indexPath.row/10*SCREEN_WIDTH*4/3+SCREEN_WIDTH*7/6);

           break;

       case 9:

            center =CGPointMake(SCREEN_WIDTH*2/3, indexPath.row/10*SCREEN_WIDTH*4/3+SCREEN_WIDTH*7/6);

           break;

       default:

           break;

    }

    attributes.size = cellSize;

    //定义各单元格的中心

    attributes.center = center;

   return attributes;

}

//返回值控制制定CGRect返回内各单元格的大小和位置

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect

{

    NSMutableArray *attributes = [NSMutableArrayarray];

    //将上面方法的返回值添加到数组中

   for (NSUInteger i =0; i < _cellCount; i ++)

    {

       NSIndexPath *indexPath = [NSIndexPathindexPathForItem:i inSection:0];

        [attributes addObject:[selflayoutAttributesForItemAtIndexPath:indexPath]];

    }

   return attributes;

}


是不是比较容易看明白,分别实现几个功能:初始化,定义网格内容大小(CGSize),指定单元格的大小和位置,还有其他一些方法在文章最后有所涉及。


2.将CollectionView的布局对象设为上面布局类。


FXLayout *flowLayout = [[FXLayoutalloc]init];


    UICollectionView *collectionView = [[UICollectionViewalloc] initWithFrame:CGRectMake(0,64, 320, SCREEN_HEIGHT-64) collectionViewLayout:flowLayout];

    [collectionView registerClass:[UICollectionViewCellclass] forCellWithReuseIdentifier:@"cellId"];

    collectionView.delegate =self;

    collectionView.dataSource =self;

    //collectionView.minimumZoomScale = 0.5;

    collectionView.backgroundColor =COLOR(237, 237, 237);

    [self.viewaddSubview:collectionView];

这一步很容易,记得实现UIConllectionViewDataSource和UICollectionViewDelegate两个协议就好了。

3.如前面所说,还要实现一些基本方法(定义单元格数量,内容等),

//定义展示的cell数量

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

{

    return_imageArray.count;

}


//展示的Section个数

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView

{

   return 1;

}

//定义每个cell的内容

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

{

    //static NSString *cellId = @"cellId";

    UICollectionViewCell *cell = [collectionViewdequeueReusableCellWithReuseIdentifier:@"cellId"forIndexPath:indexPath];

    //先移除再加载

    for (UIView *viewin cell.contentView.subviews) {

        [view removeFromSuperview];

    }

    cell.backgroundColor = [UIColorwhiteColor];

    cell.layer.borderColor =CGCOLOR(208,208, 208);//CGCOLOR(208, 208, 208)

    cell.layer.borderWidth =0.5;

    if (_titleArray.count>=1 && _imageArray.count>=1)

    {

       if (indexPath.row%10 ==3 || indexPath.row%10 ==9)

        {

           UIImageView *imageView = [[UIImageViewalloc]initWithFrame:CGRectMake(cell.frame.size.width/2-40,3, 80,80)];

            imageView.image = [_imageArrayobjectAtIndex:indexPath.row];

            [cell.contentViewaddSubview:imageView];

            

           UILabel *titleLabel = [[UILabelalloc]initWithFrame:CGRectMake(0, cell.frame.size.height-45, cell.frame.size.width,40)];

            titleLabel.text = [_titleArrayobjectAtIndex:indexPath.row];

            titleLabel.textColor =COLOR(102, 102, 102);

            titleLabel.font = [UIFontsystemFontOfSize:12];

            titleLabel.numberOfLines =0;

            titleLabel.textAlignment =NSTextAlignmentCenter;

            [cell.contentViewaddSubview:titleLabel];

        }

       else

        {

        //要不将图片和标题统一到图片?图片是方形的

       UIImageView *imageView = [[UIImageViewalloc]initWithFrame:CGRectMake(23,10, 60,60)];

        imageView.image = [_imageArrayobjectAtIndex:indexPath.row];

        [cell.contentViewaddSubview:imageView];

        

       UILabel *titleLabel = [[UILabelalloc]initWithFrame:CGRectMake(0,cell.frame.size.height-45, cell.frame.size.width,40)];

        titleLabel.text = [_titleArrayobjectAtIndex:indexPath.row];

        titleLabel.textColor =COLOR(102, 102, 102);

            titleLabel.font = [UIFontsystemFontOfSize:12];

            titleLabel.numberOfLines =0;

        titleLabel.textAlignment =NSTextAlignmentCenter;

        [cell.contentViewaddSubview:titleLabel];

        }

    }

    

   return cell;

}


//cell被选中时的方法

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath

{

   NSLog(@"你选择了第%ld个单元格",(long)indexPath.row);

}

4.上面的方法能满足基本的显示网格的需求,但是其他方面还缺失一些。下面是一些扩展内容:
//单元格显示时会调用该方法,可以完成一些动画

- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath;

//单元格消失时会调用该方法

- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath;

以上两个方法都是在自定义布局类中完成的。


在collectionView中,从点击单元格到离开单元格会依次调用以下方法(可以实现遮罩的效果):

- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath;

- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath;

- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath;

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath;

目前就研究了这些方法,以后还有收获再分享。


转载请注明转载地址:(与众相得的博客)http://write.blog.csdn.net/postlist




0 0