自定义UICollectionView的布局

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


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

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

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

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

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

不多说了,上代码:

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

- (void)prepareLayout

{

    [super prepareLayout];

    

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

    _cellCount = [[self collectionView] 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 = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath: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 = [NSMutableArray array];

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

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

    {

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

        [attributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];

    }

    return attributes;

}


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


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


FXLayout *flowLayout = [[FXLayout alloc]init];


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

    [collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cellId"];

    collectionView.delegate = self;

    collectionView.dataSource = self;

    //collectionView.minimumZoomScale = 0.5;

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

    [self.view addSubview: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 = [collectionView dequeueReusableCellWithReuseIdentifier:@"cellId" forIndexPath:indexPath];

    //先移除再加载

    for (UIView *view in cell.contentView.subviews) {

        [view removeFromSuperview];

    }

    cell.backgroundColor = [UIColor whiteColor];

    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 = [[UIImageView alloc]initWithFrame:CGRectMake(cell.frame.size.width/2-40, 3, 80,80)];

            imageView.image = [_imageArray objectAtIndex:indexPath.row];

            [cell.contentView addSubview:imageView];

            

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

            titleLabel.text = [_titleArray objectAtIndex:indexPath.row];

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

            titleLabel.font = [UIFont systemFontOfSize:12];

            titleLabel.numberOfLines = 0;

            titleLabel.textAlignment = NSTextAlignmentCenter;

            [cell.contentView addSubview:titleLabel];

        }

        else

        {

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

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

        imageView.image = [_imageArray objectAtIndex:indexPath.row];

        [cell.contentView addSubview:imageView];

        

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

        titleLabel.text = [_titleArray objectAtIndex:indexPath.row];

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

            titleLabel.font = [UIFont systemFontOfSize:12];

            titleLabel.numberOfLines = 0;

        titleLabel.textAlignment = NSTextAlignmentCenter;

        [cell.contentView addSubview: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




你可能感兴趣的:(ios,单元格,网格,自定义布局)