美文网首页
iOS UICollectionView

iOS UICollectionView

作者: 搬砖的crystal | 来源:发表于2021-09-14 15:56 被阅读0次

    UICollectionview是iOS6之后引入的UI控件,继承自UIScrollVie。它和UITableview有着许多的相似之处,但是它是一个比UITableView更加强大的一个视图控件,使用过程中需要实现数据源以及代理方法,其特点如下:

    • 系统自带的流水布局支持水平和垂直两种方式的布局;
    • 通过layout配置方式进行布局;
    • collectionview中item的大小和位置可以自定义;
    • 可以自定义一套layout的布局方案
    (1)遵循两个协议
    • 数据源协议UICollectionViewDataSource
    • 代理方法协议UICollectionViewDelegate
    (2)注册cell
     [collectionView registerClass:[MyCollectionViewCell class] forCellWithReuseIdentifier:@"cellID"];
    
    (3)布局类

    系统提供了两个布局类:

    • UICollectionViewLayout:是一个抽象类,我们在自定义布局的时候可以继承此类,并在此基础上设置布局信息。
    • UICollectionViewFlowLayout:继承于UICollectionViewLayout,是系统写好的布局类,该类为我们提供了一个简单的布局样式。假如我们只需要一个特别简单的网格布局或者流水布局,可以直接使用它。
    1.简单使用
    //
    //  ViewController.m
    //  DJTestDemo
    //
    //  Created by admin on 2021/6/8.
    //
    
    #import "ViewController.h"
    #import "DJCollectionViewCell.h"
    @interface ViewController ()<UICollectionViewDelegate,UICollectionViewDataSource>
    
    @property(nonatomic,strong)UICollectionView *collrctionView;
    
    @end
    @implementation ViewController
    
    -(void)viewDidLoad{
        [super viewDidLoad];
        self.view.backgroundColor = [UIColor orangeColor];
        [self.view addSubview:self.collrctionView];
    }
    
    #pragma mark - UICollectionViewDelegate
    - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
        return 2;
    }
    - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    
        return 20;
    }
    
    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
    {
        //创建item 从缓存池中拿 Item
        UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"DJCollectionViewCell" forIndexPath:indexPath];
        if(!cell){
            cell = [[UICollectionViewCell alloc] init];
        }
        CGFloat red = arc4random()%256/255.0;
        CGFloat green = arc4random()%256/255.0;
        CGFloat blue = arc4random()%256/255.0;
        cell.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1];
        return cell;
    
    }
    
    - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath{
        if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
            UICollectionReusableView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"headerView" forIndexPath:indexPath];
            UILabel *view = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 40)];
            view.backgroundColor = [UIColor orangeColor];
            view.text = @"headerView";
            [headerView addSubview:view];
            return headerView;
        }else{
            UICollectionReusableView *footerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"footerView" forIndexPath:indexPath];
            UILabel *view = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 40)];
            view.backgroundColor = [UIColor greenColor];
            view.text = @"footerView";
            [footerView addSubview:view];
            return footerView;
        }
    }
    
    #pragma mark - 点击 某个Item时 调用
    - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
        //取消选中
        [collectionView deselectItemAtIndexPath:indexPath animated:YES];
    }
    
    -(UICollectionView *)collrctionView{
        if (!_collrctionView) {
            
            UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
            // 设置item的行间距和列间距
            layout.minimumInteritemSpacing = 15;
            layout.minimumLineSpacing = 15;
            // 设置item的大小
            CGFloat itemW = ([UIScreen mainScreen].bounds.size.width - 65) /4 ;
            layout.itemSize = CGSizeMake(itemW, itemW);
            layout.headerReferenceSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, 40);
            layout.footerReferenceSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, 40);
            // 设置每个分区的 上左下右 的内边距
            layout.sectionInset = UIEdgeInsetsMake(10, 10 ,10, 10);
    //        // 设置区头和区尾的大小
    //        layout.headerReferenceSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, 10);
    //        layout.footerReferenceSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, 10);
    //        // 设置分区的头视图和尾视图 是否始终固定在屏幕上边和下边
    //        layout.sectionFootersPinToVisibleBounds = YES;
            // 设置滚动条方向
    //        layout.scrollDirection = UICollectionViewScrollDirectionVertical;
            
            _collrctionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height-100) collectionViewLayout:layout];
            _collrctionView.backgroundColor = [UIColor whiteColor];
    //        _collrctionView.showsVerticalScrollIndicator = NO;
            _collrctionView.scrollEnabled = YES;
            
            //注册cell
            [_collrctionView registerClass:[DJCollectionViewCell class] forCellWithReuseIdentifier:@"DJCollectionViewCell"];
            [_collrctionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"footerView"];
            [_collrctionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"headerView"];
    
            _collrctionView.delegate = self;
            _collrctionView.dataSource = self;
        }
        return _collrctionView;
    }
    
    
    @end
    
    2.瀑布流

    瀑布流的特点:
    (1)瀑布流的列数是固定的,不会动态改变。
    (2)每个Item的高都不是固定的,是由Item的内容决定的。
    (3)布局时Item总是加到高度比较小的那一列上。

    DJCollectionWaterfallLayout的头文件,继承UICollectionViewLayout:

    //
    //  DJCollectionWaterfallLayout.h
    //  DJTestDemo
    //
    //  Created by admin on 2021/9/14.
    //
    
    #import <UIKit/UIKit.h>
    
    extern NSString *const kSupplementaryViewKindHeader;
    
    @protocol DJCollectionWaterfallLayoutProtocol;
    @interface DJCollectionWaterfallLayout : UICollectionViewLayout
    
    @property (nonatomic, weak) id<DJCollectionWaterfallLayoutProtocol> delegate;
    //行数
    @property (nonatomic, assign) NSUInteger columns;
    //列间距
    @property (nonatomic, assign) CGFloat columnSpacing;
    //行间距
    @property (nonatomic, assign) CGFloat itemSpacing;
    //section到collectionView的边距
    @property (nonatomic, assign) UIEdgeInsets insets;
    
    @end
    
    @protocol DJCollectionWaterfallLayoutProtocol <NSObject>
    
    - (CGFloat)collectionViewLayout:(DJCollectionWaterfallLayout *)layout heightForItemAtIndexPath:(NSIndexPath *)indexPath;
    
    - (CGFloat)collectionViewLayout:(DJCollectionWaterfallLayout *)layout heightForSupplementaryViewAtIndexPath:(NSIndexPath *)indexPath;
    
    @end
    
    //
    //  DJCollectionWaterfallLayout.m
    //  DJTestDemo
    //
    //  Created by admin on 2021/9/14.
    //
    
    #import "DJCollectionWaterfallLayout.h"
    
    NSString *const kSupplementaryViewKindHeader = @"Header";
    CGFloat const kSupplementaryViewKindHeaderPinnedHeight = 44.f;
    
    @interface DJCollectionWaterfallLayout()
    
    /** 保存所有Item的LayoutAttributes */
    @property (nonatomic, strong) NSMutableArray<UICollectionViewLayoutAttributes *> *attributesArray;
    /** 保存所有列的当前高度 */
    @property (nonatomic, strong) NSMutableArray<NSNumber *> *columnHeights;
    
    @end
    
    @implementation DJCollectionWaterfallLayout
    
    - (void)dealloc
    {
        NSLog(@"%s", __func__);
    }
    
    - (instancetype)init
    {
        if(self = [super init]) {
            _columns = 1;
            _columnSpacing = 10;
            _itemSpacing = 10;
            _insets = UIEdgeInsetsZero;
        }
        return self;
    }
    
    #pragma mark - UICollectionViewLayout (UISubclassingHooks)
    /**
     *  1、
     *  collectionView初次显示或者调用invalidateLayout方法后会调用此方法
     *  触发此方法会重新计算布局,每次布局也是从此方法开始
     *  在此方法中需要做的事情是准备后续计算所需的东西,以得出后面的ContentSize和每个item的layoutAttributes
     */
    - (void)prepareLayout
    {
        [super prepareLayout];
        
        
        //初始化数组
        self.columnHeights = [NSMutableArray array];
        for(NSInteger column=0; column<_columns; column++){
            self.columnHeights[column] = @(0);
        }
        
        
        self.attributesArray = [NSMutableArray array];
        NSInteger numSections = [self.collectionView numberOfSections];
        for(NSInteger section=0; section<numSections; section++){
            NSInteger numItems = [self.collectionView numberOfItemsInSection:0];
            for(NSInteger item=0; item<numItems; item++){
                //遍历每一项
                NSIndexPath *indexPath = [NSIndexPath indexPathForItem:item inSection:section];
                //计算LayoutAttributes
                UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];
                
                [self.attributesArray addObject:attributes];
            }
        }
    }
    
    /**
     *  2、
     *  需要返回所有内容的滚动长度
     */
    - (CGSize)collectionViewContentSize
    {
        NSInteger mostColumn = [self columnOfMostHeight];
        //所有列当中最大的高度
        CGFloat mostHeight = [self.columnHeights[mostColumn] floatValue];
        return CGSizeMake(self.collectionView.bounds.size.width, mostHeight+_insets.top+_insets.bottom);
    }
    
    /**
     *  3、
     *  当CollectionView开始刷新后,会调用此方法并传递rect参数(即当前可视区域)
     *  我们需要利用rect参数判断出在当前可视区域中有哪几个indexPath会被显示(无视rect而全部计算将会带来不好的性能)
     *  最后计算相关indexPath的layoutAttributes,加入数组中并返回
     */
    - (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
    {
        NSMutableArray *attributesArray = self.attributesArray;
        NSArray<NSIndexPath *> *indexPaths;
        //1、计算rect中出现的items
        indexPaths = [self indexPathForItemsInRect:rect];
        for(NSIndexPath *indexPath in indexPaths){
            //计算对应的LayoutAttributes
            UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:indexPath];
            [attributesArray addObject:attributes];
        }
        
        //2、计算rect中出现的SupplementaryViews
        //这里只计算了kSupplementaryViewKindHeader
        indexPaths = [self indexPathForSupplementaryViewsOfKind:kSupplementaryViewKindHeader InRect:rect];
        for(NSIndexPath *indexPath in indexPaths){
            //计算对应的LayoutAttributes
            UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:kSupplementaryViewKindHeader atIndexPath:indexPath];
            [attributesArray addObject:attributes];
        }
        
        return attributesArray;
    }
    
    /**
     *  每当offset改变时,是否需要重新布局,newBounds为offset改变后的rect
     *  瀑布流中不需要,因为滑动时,cell的布局不会随offset而改变
     *  如果需要实现悬浮Header,需要改为YES
     */
    - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
    {
        //return [super shouldInvalidateLayoutForBoundsChange:newBounds];
        return YES;
    }
    
    #pragma mark - 计算单个indexPath的LayoutAttributes
    /**
     *  根据indexPath,计算对应的LayoutAttributes
     */
    - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
    {
        UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
        //外部返回Item高度
        CGFloat itemHeight = [self.delegate collectionViewLayout:self heightForItemAtIndexPath:indexPath];
        
        //headerView高度
        CGFloat headerHeight = [self.delegate collectionViewLayout:self heightForSupplementaryViewAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
        
        //找出所有列中高度最小的
        NSInteger columnIndex = [self columnOfLessHeight];
        CGFloat lessHeight = [self.columnHeights[columnIndex] floatValue];
        
        //计算LayoutAttributes
        CGFloat width = (self.collectionView.bounds.size.width-(_insets.left+_insets.right)-_columnSpacing*(_columns-1)) / _columns;
        CGFloat height = itemHeight;
        CGFloat x = _insets.left+(width+_columnSpacing)*columnIndex;
        CGFloat y = lessHeight==0 ? headerHeight+_insets.top : lessHeight+_itemSpacing;
        attributes.frame = CGRectMake(x, y, width, height);
        
        //更新列高度
        self.columnHeights[columnIndex] = @(y+height);
        
        return attributes;
    }
    
    /**
     *  根据kind、indexPath,计算对应的LayoutAttributes
     */
    - (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath
    {
        UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:elementKind withIndexPath:indexPath];
        
        //计算LayoutAttributes
        if([elementKind isEqualToString:kSupplementaryViewKindHeader]){
            CGFloat width = self.collectionView.bounds.size.width;
            CGFloat height = [self.delegate collectionViewLayout:self heightForSupplementaryViewAtIndexPath:indexPath];
            CGFloat x = 0;
            //根据offset计算kSupplementaryViewKindHeader的y
            //y = offset.y-(header高度-固定高度)
            CGFloat offsetY = self.collectionView.contentOffset.y;
            CGFloat y = MAX(0,
                            offsetY-(height-kSupplementaryViewKindHeaderPinnedHeight));
            attributes.frame = CGRectMake(x, y, width, height);
            attributes.zIndex = 1024;
        }
        return attributes;
    }
    
    
    #pragma mark - helpers
    /**
     *  找到高度最小的那一列的下标
     */
    - (NSInteger)columnOfLessHeight
    {
        if(self.columnHeights.count == 0 || self.columnHeights.count == 1){
            return 0;
        }
    
        __block NSInteger leastIndex = 0;
        [self.columnHeights enumerateObjectsUsingBlock:^(NSNumber *number, NSUInteger idx, BOOL *stop) {
            
            if([number floatValue] < [self.columnHeights[leastIndex] floatValue]){
                leastIndex = idx;
            }
        }];
        
        return leastIndex;
    }
    
    /**
     *  找到高度最大的那一列的下标
     */
    - (NSInteger)columnOfMostHeight
    {
        if(self.columnHeights.count == 0 || self.columnHeights.count == 1){
            return 0;
        }
        
        __block NSInteger mostIndex = 0;
        [self.columnHeights enumerateObjectsUsingBlock:^(NSNumber *number, NSUInteger idx, BOOL *stop) {
            
            if([number floatValue] > [self.columnHeights[mostIndex] floatValue]){
                mostIndex = idx;
            }
        }];
        
        return mostIndex;
    }
    
    #pragma mark - 根据rect返回应该出现的Items
    /**
     *  计算目标rect中含有的item
     */
    - (NSMutableArray<NSIndexPath *> *)indexPathForItemsInRect:(CGRect)rect
    {
        NSMutableArray<NSIndexPath *> *indexPaths = [NSMutableArray array];
        
        
        return indexPaths;
    }
    
    /**
     *  计算目标rect中含有的某类SupplementaryView
     */
    - (NSMutableArray<NSIndexPath *> *)indexPathForSupplementaryViewsOfKind:(NSString *)kind InRect:(CGRect)rect
    {
        NSMutableArray<NSIndexPath *> *indexPaths = [NSMutableArray array];
        if([kind isEqualToString:kSupplementaryViewKindHeader]){
            //在这个瀑布流自定义布局中,只有一个位于列表顶部的SupplementaryView
            NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
            
            //如果当前区域可以看到SupplementaryView,则返回
            //CGFloat height = [self.delegate collectionViewLayout:self heightForSupplementaryViewAtIndexPath:indexPath];
            //if(CGRectGetMinY(rect) <= height + _insets.top){
            //Header默认总是需要显示
            [indexPaths addObject:indexPath];
            //}
        }
        
        
        return indexPaths;
    }
    
    @end
    
    //
    //  ViewController.m
    //  DJTestDemo
    //
    //  Created by admin on 2021/6/8.
    //
    
    #import "ViewController.h"
    #import "DJCollectionWaterfallLayout.h"
    @interface ViewController ()<UICollectionViewDelegate,UICollectionViewDataSource,DJCollectionWaterfallLayoutProtocol>
    
    @property(nonatomic,strong)UICollectionView *collrctionView;
    @property (nonatomic, strong) NSMutableArray *dataList;
    @property (nonatomic, strong) DJCollectionWaterfallLayout *waterfallLayout;
    
    @end
    @implementation ViewController
    
    -(void)viewDidLoad{
        [super viewDidLoad];
        [self setupDataList];
        [self.view addSubview:self.collrctionView];
    }
    
    #pragma mark - 数据源
    - (void)setupDataList{
        _dataList = [NSMutableArray array];
        NSInteger dataCount = arc4random()%25+50;
        for(NSInteger i=0; i<dataCount; i++){
            NSInteger rowHeight = arc4random()%100+200;
            [_dataList addObject:@(rowHeight)];
        }
        
    }
    
    #pragma mark - UICollectionViewDelegate
    - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
        return 2;
    }
    - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    
        return _dataList.count;
    }
    
    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
    {
        //创建item 从缓存池中拿 Item
        UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"DJCollectionViewCell" forIndexPath:indexPath];
        if(!cell){
            cell = [[UICollectionViewCell alloc] init];
        }
        CGFloat red = arc4random()%256/255.0;
        CGFloat green = arc4random()%256/255.0;
        CGFloat blue = arc4random()%256/255.0;
        cell.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1];
        return cell;
    
    }
    
    - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath{
        if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
            UICollectionReusableView *headerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"headerView" forIndexPath:indexPath];
            UILabel *view = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 40)];
            view.backgroundColor = [UIColor orangeColor];
            view.text = @"headerView";
            [headerView addSubview:view];
            return headerView;
        }else{
            UICollectionReusableView *footerView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"footerView" forIndexPath:indexPath];
            UILabel *view = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 40)];
            view.backgroundColor = [UIColor greenColor];
            view.text = @"footerView";
            [footerView addSubview:view];
            return footerView;
        }
    }
    
    #pragma mark - CollectionWaterfallLayoutProtocol
    - (CGFloat)collectionViewLayout:(DJCollectionWaterfallLayout *)layout heightForItemAtIndexPath:(NSIndexPath *)indexPath{
        NSInteger row = indexPath.row;
        CGFloat cellHeight = [_dataList[row] floatValue];
        return cellHeight;
    }
    
    - (CGFloat)collectionViewLayout:(DJCollectionWaterfallLayout *)layout heightForSupplementaryViewAtIndexPath:(NSIndexPath *)indexPath{
       
        return 0;
    }
    
    #pragma mark - 点击 某个Item时 调用
    - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
        //取消选中
        [collectionView deselectItemAtIndexPath:indexPath animated:YES];
    }
    
    -(UICollectionView *)collrctionView{
        if (!_collrctionView) {
            
            _waterfallLayout = [[DJCollectionWaterfallLayout alloc] init];
            _waterfallLayout.delegate = self;
            _waterfallLayout.columns = 4;
            _waterfallLayout.columnSpacing = 10;
            _waterfallLayout.insets = UIEdgeInsetsMake(10, 10, 10, 10);
            
            _collrctionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height-100) collectionViewLayout:_waterfallLayout];
            _collrctionView.backgroundColor = [UIColor whiteColor];
    //        _collrctionView.showsVerticalScrollIndicator = NO;
            _collrctionView.scrollEnabled = YES;
            
            //注册cell
            [_collrctionView registerClass:[DJCollectionViewCell class] forCellWithReuseIdentifier:@"DJCollectionViewCell"];
            [_collrctionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"footerView"];
            [_collrctionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"headerView"];
    
            _collrctionView.delegate = self;
            _collrctionView.dataSource = self;
        }
        return _collrctionView;
    }
    
    
    @end
    
    3. UICollectionViewLayout

    一旦UICollectionView需要刷新(放到屏幕上或需要reloadData)或者被标记为需要重新计算布局(调用了layout对象的invalidateLayout方法)时,UICollectionView就会向布局对象请求一系列的方法:

    (1)首先会调用prepareLayout方法,在此方法中尽可能将后续布局时需要用到的前置计算处理好,每次重新布局都是从此方法开始。
    (2)调用collectionViewContentSize方法,根据第一点中的计算来返回所有内容的滚动区域大小。
    (3)调用layoutAttributesForElementsInRect:方法,计算rect内相应的布局,并返回一个装有UICollectionViewLayoutAttributes的数组,Attributes 跟所有Item一一对应,UICollectionView就是根据这个Attributes来对Item进行布局,并当新的Rect区域滚动进入屏幕时再次请求此方法。
    (4)在layoutAttributesForElementsInRect:方法中,可以单独访问-layoutAttributesForItemAtIndexPath:方法,来根据indexPath来请求layoutAttributes,虽然这一步不是必须的。

    相关文章

      网友评论

          本文标题:iOS UICollectionView

          本文链接:https://www.haomeiwen.com/subject/ahecgltx.html