横向分页滚动的UICollectionView,cell左右排版 支持多组Cell实现。

需求:固定高度一个区域,里面左右分页显示很多个图标,在每一页中的图标先从左往右排,排满后再从上往下排。这一页排满后排下一页。


像这样的需求,第一反应是用UICollectionView来写,用UICollectionViewFlowLayout,然后设置为横向的。
但是,显示出来肯定上下上下排版的。下面的图是我借来的。。如果原创的看到这张图莫怪哈。。


这样显示方式就是系统自带的。
我们如果要横向现实。。那我们要如何实现呢? 其实很简单。重写一个 UICollectionViewFlowLayout 就可以的了。

自定义的UICollectionViewLayout

UICollectionViewLayout的功能为向UICollectionView提供布局信息,不仅包括cell的布局信息,也包括追加视图和装饰视图的布局信息。实现一个自定义layout的常规做法是继承UICollectionViewLayout类,然后重载下列方法:

  • -(CGSize)collectionViewContentSize

    • 返回collectionView的内容的尺寸
  • -(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect

    • 返回rect中的所有的元素的布局属性
    • 返回的是包含UICollectionViewLayoutAttributes的NSArray
    • UICollectionViewLayoutAttributes可以是cell,追加视图或装饰视图的信息,通过不同的UICollectionViewLayoutAttributes初始化方法可以得到不同类型的UICollectionViewLayoutAttributes:

      • layoutAttributesForCellWithIndexPath:
      • layoutAttributesForSupplementaryViewOfKind:withIndexPath:
      • layoutAttributesForDecorationViewOfKind:withIndexPath:
  • -(UICollectionViewLayoutAttributes )layoutAttributesForItemAtIndexPath:(NSIndexPath )indexPath

    • 返回对应于indexPath的位置的cell的布局属性
  • -(UICollectionViewLayoutAttributes )layoutAttributesForSupplementaryViewOfKind:(NSString )kind atIndexPath:(NSIndexPath *)indexPath

    • 返回对应于indexPath的位置的追加视图的布局属性,如果没有追加视图可不重载
  • -(UICollectionViewLayoutAttributes * )layoutAttributesForDecorationViewOfKind:(NSString)decorationViewKind atIndexPath:(NSIndexPath )indexPath

    • 返回对应于indexPath的位置的装饰视图的布局属性,如果没有装饰视图可不重载
  • -(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds

    • 当边界发生改变时,是否应该刷新布局。如果YES则在边界变化(一般是scroll到其他地方)时,将重新计算需要的布局信息。
好了,带大家了解自定义ectionViewFlowLayout 的一些必须重载方法,那么现在就开始上实现代码了。

#import <UIKit/UIKit.h>


@interface BCCollectionViewHorizontalLayout : UICollectionViewFlowLayout


//  一行中 cell 的个数

@property (nonatomic,assign) NSUInteger itemCountPerRow;


//    一页显示多少行

@property (nonatomic,assign) NSUInteger rowCount;


@end



#import "BCCollectionViewHorizontalLayout.h"


@interface BCCollectionViewHorizontalLayout () <UICollectionViewDelegateFlowLayout>

@property (strong, nonatomic) NSMutableArray *allAttributes;

@end


@implementation BCCollectionViewHorizontalLayout


-(instancetype)init

{

    if (self = [super init])

    {

        

    }

    return self;

}


- (void)prepareLayout

{

    [super prepareLayout];

    

    self.allAttributes = [NSMutableArray array];

    

    NSInteger sections = [self.collectionView numberOfSections];

    for (int i = 0; i < sections; i++)

    {

        NSMutableArray * tmpArray = [NSMutableArray array];

        NSUInteger count = [self.collectionView numberOfItemsInSection:i];

        

        for (NSUInteger j = 0; j<count; j++) {

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

            UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];

            [tmpArray addObject:attributes];

        }


        [self.allAttributes addObject:tmpArray];

    }

}


- (CGSize)collectionViewContentSize

{

    return [super collectionViewContentSize];

}


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

{

    NSUInteger item = indexPath.item;

    NSUInteger x;

    NSUInteger y;

    [self targetPositionWithItem:item resultX:&x resultY:&y];

    NSUInteger item2 = [self originItemAtX:x y:y];

    NSIndexPath *theNewIndexPath = [NSIndexPath indexPathForItem:item2 inSection:indexPath.section];

    

    UICollectionViewLayoutAttributes *theNewAttr = [super layoutAttributesForItemAtIndexPath:theNewIndexPath];

    theNewAttr.indexPath = indexPath;

    return theNewAttr;

}


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

{

    NSArray *attributes = [super layoutAttributesForElementsInRect:rect];

    

    NSMutableArray *tmp = [NSMutableArray array];

    

    for (UICollectionViewLayoutAttributes *attr in attributes) {

        for (NSMutableArray *attributes in self.allAttributes)

        {

            for (UICollectionViewLayoutAttributes *attr2 in attributes) {

                if (attr.indexPath.item == attr2.indexPath.item) {

                    [tmp addObject:attr2];

                    break;

                }

            }


        }

    }

    return tmp;

}



- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds

{

    return YES;

}


// 根据 item 计算目标item的位置

// x 横向偏移  y 竖向偏移

- (void)targetPositionWithItem:(NSUInteger)item

                       resultX:(NSUInteger *)x

                       resultY:(NSUInteger *)y

{

    NSUInteger page = item/(self.itemCountPerRow*self.rowCount);

    

    NSUInteger theX = item % self.itemCountPerRow + page * self.itemCountPerRow;

    NSUInteger theY = item / self.itemCountPerRow - page * self.rowCount;

    if (x != NULL) {

        *x = theX;

    }

    if (y != NULL) {

        *y = theY;

    }

}


// 根据偏移量计算item

- (NSUInteger)originItemAtX:(NSUInteger)x

                          y:(NSUInteger)y

{

    NSUInteger item = x * self.rowCount + y;

    return item;

}

@end


好啦,代码演示到这也就结束了。希望这篇文章对进来看的朋友有帮助。
觉得有帮助的朋友不妨动动你的小手。帮忙点下赞,谢谢。












































评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值