• iOS学习笔记33-UICollectionView入门


    一、UICollectionView介绍

    UICollectionViewUICollectionViewController类是iOS6新引进的API,用于展示集合视图,布局更加灵活,可实现多列布局,用法类似于UITableViewUITableViewController类,但也有所不同。
    UICollectionView可以实现如下效果,也是一个常用的控件:

    二、UICollectiomView使用

    UICollectionView的创建和UITableView的创建有所不同:

    1. UITableView的创建只需要设置frame即可使用
      UICollectionView除了需要frame,还需要一个布局参数

      -(id)initWithFrame:(CGRect)frame /* 尺寸 */
          collectionViewLayout:(UICollectionViewLayout *)layout;/* 布局参数 */
    2. UITableView可以不需要注册Cell视图类,手动创建Cell视图类
      UICollectionView必须注册视图类,才能显示,不需要手动创建

    UICollectionView的布局参数:
    1. 是一个UICollectionViewLayout类的对象,
      但我们一般使用它的子类UICollectionViewFlowLayout
    2. 设置布局对象的滚动方向属性scrollDirection

      typedef NS_ENUM(NSInteger, UICollectionViewScrollDirection) {     
          UICollectionViewScrollDirectionVertical,  /*垂直滚动*/  
          UICollectionViewScrollDirectionHorizontal /* 水平滚动 */
      };
    3. 垂直滚动,表示Cell方块布局是从左往右,从上到下排列的布局
    4. 水平滚动,表示Cell方块布局是从上往下,从左到右排列的布局
    5. UITableView不同,UICollectionView只能在这里设置顶部视图和底部视图的大小
    6. 设置为垂直滚动时,顶部和底部视图的宽度为UICollectionView的宽度,无法设置
    7. 设置为水平滚动时,顶部和底部视图的高度为UICollectionView的高度,无法设置

    UICollectionView的常用对象方法
    /* 向容器视图注册Cell方块视图,有2种方式,一种是类名注册,一种是Xib注册 */
    - (void)registerClass:(Class)cellClass /* 视图类 */
            forCellWithReuseIdentifier:(NSString *)identifier;/* 绑定标识 */
    - (void)registerNib:(UINib *)nib /* Xib */
            forCellWithReuseIdentifier:(NSString *)identifier;/* 绑定标识 */
    
    /* 从缓存池中取出Cell方块视图对象,如果缓存池没有,自动调用alloc/initWithFrame创建 */
    - (UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier 
                              forIndexPath:(NSIndexPath *)indexPath;
    
    /* kind参数设置 */
    NSString *const UICollectionElementKindSectionHeader;/* 顶部视图用这个 */
    NSString *const UICollectionElementKindSectionFooter;/* 底部视图用这个 */
    /* 向容器视图注册顶部视图或者底部视图,有2种方式,一种是类名注册,一种是Xib注册 */
    - (void)registerClass:(Class)viewClass 
            forSupplementaryViewOfKind:(NSString *)kind /* 参考上面 */
                   withReuseIdentifier:(NSString *)identifier;/* 绑定标识 */
    - (void)registerNib:(UINib *)nib 
            forSupplementaryViewOfKind:(NSString *)kind /* 参考上面 */
                   withReuseIdentifier:(NSString *)identifier;/* 绑定标识 */
    
    /* 从缓存池中取出顶部视图对象或者底部视图对象,如果缓存池没有,自动调用alloc/initWithFrame创建 */
    - (UICollectionReusableView *)dequeueReusableSupplementaryViewOfKind:(NSString *)kind 
                                  withReuseIdentifier:(NSString *)identifier 
                                         forIndexPath:(NSIndexPath *)indexPath;
    
    
    UICollectionView的数据源方法
    @required
    /* 设置容器视图各个组都有多少个Cell方块 */
    - (NSInteger)collectionView:(UICollectionView *)collectionView 
         numberOfItemsInSection:(NSInteger)section;
    /* 设置Cell方块视图,类似于UITableViewCell的设置 */
    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView 
                      cellForItemAtIndexPath:(NSIndexPath *)indexPath;
    @optional
    /* 容器视图有多少个组,默认返回1 */
    - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView;
    /* 设置顶部视图和底部视图,通过kind参数分辨是设置顶部还是底部 */
    - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView 
               viewForSupplementaryElementOfKind:(NSString *)kind 
                                     atIndexPath:(NSIndexPath *)indexPath;
    
    UICollectionViewDelegate的常用方法
    /* 选中Cell方块时调用 */
    - (void)collectionView:(UICollectionView *)collectionView 
            didSelectItemAtIndexPath:(NSIndexPath *)indexPath;
    /* 取消选中Cell方块时调用 */
    - (void)collectionView:(UICollectionView *)collectionView 
            didDeselectItemAtIndexPath:(NSIndexPath *)indexPath;

    我们使用更多的是UICollectionViewDelegate子协议UICollectionViewDelegateFlowLayout
    该协议不仅包含父协议所有方法,还可以进行一些布局设置

    UICollectionViewDelegateFlowLayout的常用布局方法
    /* 设置每个方块的尺寸大小 */
    - (CGSize)collectionView:(UICollectionView *)collectionView 
                      layout:(UICollectionViewLayout*)collectionViewLayout 
      sizeForItemAtIndexPath:(NSIndexPath *)indexPath;
    /* 设置方块视图和边界的上下左右间距 */
    - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView 
                            layout:(UICollectionViewLayout*)collectionViewLayout 
            insetForSectionAtIndex:(NSInteger)section;

    下面是我自定义的Cell视图类、顶部视图类、底部视图类,目录结构如下:

    方块视图LTCollectionViewCell.h
    #import <UIKit/UIKit.h>
    @interface LTCollectionViewCell : UICollectionViewCell
    @property (strong, nonatomic) UILabel *textLabel;
    /* 方块视图的缓存池标示 */
    + (NSString *)cellIdentifier;
    /* 获取方块视图对象 */
    + (instancetype)cellWithCollectionView:(UICollectionView *)collectionView
                              forIndexPath:(NSIndexPath *)indexPath;
    @end
    方块视图LTCollectionViewCell.m
    #import "LTCollectionViewCell.h"
    @implementation LTCollectionViewCell
    /* 方块视图的缓存池标示 */
    + (NSString *)cellIdentifier{
        static NSString *cellIdentifier = @"CollectionViewCellIdentifier";
        return cellIdentifier;
    }
    /* 获取方块视图对象 */
    + (instancetype)cellWithCollectionView:(UICollectionView *)collectionView
                              forIndexPath:(NSIndexPath *)indexPath
    {
        //从缓存池中寻找方块视图对象,如果没有,该方法自动调用alloc/initWithFrame创建一个新的方块视图返回
        LTCollectionViewCell *cell = 
            [collectionView dequeueReusableCellWithReuseIdentifier:[LTCollectionViewCell cellIdentifier]
                                                      forIndexPath:indexPath];
        return cell;
    }
    /* 注册了方块视图后,当缓存池中没有底部视图的对象时候,自动调用alloc/initWithFrame创建 */
    - (instancetype)initWithFrame:(CGRect)frame{
        if (self = [super initWithFrame:frame]) {
            //创建label
            UILabel *textLabel = [[UILabel alloc] init];
            //设置label尺寸
            CGFloat x = 5;
            CGFloat y = 5;
            CGFloat width = frame.size.width - 10;
            CGFloat height = frame.size.height - 10;
            textLabel.frame = CGRectMake(x, y, width, height);
            //设置label属性
            textLabel.numberOfLines = 0;
            textLabel.textAlignment = NSTextAlignmentCenter;
            textLabel.font = [UIFont systemFontOfSize:15];
            //添加到父控件
            [self.contentView addSubview:textLabel];
            self.textLabel = textLabel;
        }
        return self;
    }
    @end
    顶部视图LTCollectionHeaderView.h
    #import <UIKit/UIKit.h>
    @interface LTCollectionHeaderView : UICollectionReusableView
    @property (strong, nonatomic) UILabel *textLabel;
    /* 顶部视图的缓存池标示 */
    + (NSString *)headerViewIdentifier;
    /* 获取顶部视图对象 */
    + (instancetype)headerViewWithCollectionView:(UICollectionView *)collectionView
                                    forIndexPath:(NSIndexPath *)indexPath;
    @end
    顶部视图LTCollectionHeaderView.m
    #import "LTCollectionHeaderView.h"
    
    @implementation LTCollectionHeaderView
    /* 顶部视图的缓存池标示 */
    + (NSString *)headerViewIdentifier{
        static NSString *headerIdentifier = @"headerViewIdentifier";
        return headerIdentifier;
    }
    /* 获取顶部视图对象 */
    + (instancetype)headerViewWithCollectionView:(UICollectionView *)collectionView 
                                    forIndexPath:(NSIndexPath *)indexPath
    {
        //从缓存池中寻找顶部视图对象,如果没有,该方法自动调用alloc/initWithFrame创建一个新的顶部视图返回
        LTCollectionHeaderView *headerView = 
            [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader
                                               withReuseIdentifier:[LTCollectionHeaderView headerViewIdentifier]
                                                      forIndexPath:indexPath];
        return headerView;
    }
    /* 注册了顶部视图后,当缓存池中没有顶部视图的对象时候,自动调用alloc/initWithFrame创建 */
    - (instancetype)initWithFrame:(CGRect)frame{
        if (self = [super initWithFrame:frame]) {
            //创建label
            UILabel *textLabel = [[UILabel alloc] init];
            //设置label尺寸
            CGFloat x = 5;
            CGFloat y = 5;
            CGFloat width = frame.size.width - 10;
            CGFloat height = frame.size.height - 10;
            textLabel.frame = CGRectMake(x, y, width, height);
            //设置label属性
            textLabel.numberOfLines = 0;
            textLabel.textAlignment = NSTextAlignmentCenter;
            //添加到父控件
            [self addSubview:textLabel];
            self.textLabel = textLabel;
        }
        return self;
    }
    @end
    底部视图LTCollectionFooterView.h
    #import <UIKit/UIKit.h>
    @interface LTCollectionFooterView : UICollectionReusableView
    @property (strong, nonatomic) UILabel *textLabel;
    /* 底部视图的缓存池标示 */
    + (NSString *)footerViewIdentifier;
    /* 获取底部视图对象 */
    + (instancetype)footerViewWithCollectionView:(UICollectionView *)collectionView
                                    forIndexPath:(NSIndexPath *)indexPath;
    @end
    底部视图LTCollectionFooterView.m
    #import "LTCollectionFooterView.h"
    
    @implementation LTCollectionFooterView
    /* 底部视图的缓存池标示 */
    + (NSString *)footerViewIdentifier{
        static NSString *footerIdentifier = @"footerViewIdentifier";
        return footerIdentifier;
    }
    /* 获取底部视图对象 */
    + (instancetype)footerViewWithCollectionView:(UICollectionView *)collectionView
                                    forIndexPath:(NSIndexPath *)indexPath
    {
        //从缓存池中寻找底部视图对象,如果没有,该方法自动调用alloc/initWithFrame创建一个新的底部视图返回
        LTCollectionFooterView *footerView =
                [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter
                                                   withReuseIdentifier:[LTCollectionFooterView footerViewIdentifier]
                                                          forIndexPath:indexPath];
        return footerView;
    }
    /* 注册了底部视图后,当缓存池中没有底部视图的对象时候,自动调用alloc/initWithFrame创建 */
    - (instancetype)initWithFrame:(CGRect)frame{
        if (self = [super initWithFrame:frame]) {
            //创建label
            UILabel *textLabel = [[UILabel alloc] init];
            //设置label尺寸
            CGFloat x = 5;
            CGFloat y = 5;
            CGFloat width = frame.size.width - 10;
            CGFloat height = frame.size.height - 10;
            textLabel.frame = CGRectMake(x, y, width, height);
            //设置label属性
            textLabel.numberOfLines = 0;
            textLabel.textAlignment = NSTextAlignmentCenter;
            //添加到父控件
            [self addSubview:textLabel];
            self.textLabel = textLabel;
        }
        return self;
    }
    @end
    下面是使用实例:
    1. 视图控制器属性和相关方法
    #import "ViewController.h"
    #import "LTCollectionViewCell.h"
    #import "LTCollectionHeaderView.h"
    #import "LTCollectionFooterView.h"
    
    @interface ViewController () <UICollectionViewDataSource,
                                  UICollectionViewDelegateFlowLayout>
    @property (strong, nonatomic) UICollectionView *collectionView;/*< 容器视图 */
    @end
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        //初始化容器视图
        [self initCollectionView];
    }
    2. 初始化容器视图
    /* 初始化容器视图 */
    - (void)initCollectionView
    {
        CGFloat x = 0;
        CGFloat y = 20;
        CGFloat width = self.view.frame.size.width;
        CGFloat height = self.view.frame.size.height - 20;
        //创建布局对象
        UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
        //设置滚动方向为垂直滚动,说明方块是从左上到右下的布局排列方式
        layout.scrollDirection = UICollectionViewScrollDirectionVertical;
        //设置顶部视图和底部视图的大小,当滚动方向为垂直时,设置宽度无效,当滚动方向为水平时,设置高度无效
        layout.headerReferenceSize = CGSizeMake(100, 40);
        layout.footerReferenceSize = CGSizeMake(100, 40);
        //创建容器视图
        CGRect frame = CGRectMake(x, y, width, height);
        UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:frame
                                                              collectionViewLayout:layout];
        collectionView.delegate = self;//设置代理
        collectionView.dataSource = self;//设置数据源
        collectionView.backgroundColor = [UIColor whiteColor];//设置背景,默认为黑色
        //添加到主视图
        [self.view addSubview:collectionView];
        self.collectionView = collectionView;
        
        //注册容器视图中显示的方块视图
        [collectionView registerClass:[LTCollectionViewCell class]
                forCellWithReuseIdentifier:[LTCollectionViewCell cellIdentifier]];
        //注册容器视图中显示的顶部视图
        [collectionView registerClass:[LTCollectionHeaderView class]
           forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
                  withReuseIdentifier:[LTCollectionHeaderView headerViewIdentifier]];
        //注册容器视图中显示的底部视图
        [collectionView registerClass:[LTCollectionFooterView class]
           forSupplementaryViewOfKind:UICollectionElementKindSectionFooter
                  withReuseIdentifier:[LTCollectionFooterView footerViewIdentifier]];
        
    }
    3. UICollectionViewDataSource数据源方法
    #pragma mark - UICollectionViewDataSource
    /* 设置容器中有多少个组 */
    - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
        return 10;
    }
    /* 设置每个组有多少个方块 */
    - (NSInteger)collectionView:(UICollectionView *)collectionView
         numberOfItemsInSection:(NSInteger)section
    {
        return 20;
    }
    /* 设置方块的视图 */
    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
                      cellForItemAtIndexPath:(NSIndexPath *)indexPath
    {
        //获取cell视图,内部通过去缓存池中取,如果缓存池中没有,就自动创建一个新的cell
        LTCollectionViewCell *cell = 
                [LTCollectionViewCell cellWithCollectionView:collectionView
                                                forIndexPath:indexPath];
        //设置cell属性
        cell.contentView.backgroundColor = [UIColor redColor];
        cell.textLabel.text = [NSString stringWithFormat:@"Cell %2ld",indexPath.row];
        
        return cell;
    }
    /* 设置顶部视图和底部视图 */
    - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView
               viewForSupplementaryElementOfKind:(NSString *)kind
                                     atIndexPath:(NSIndexPath *)indexPath
    {
        if ( [kind isEqualToString:UICollectionElementKindSectionHeader] ) {//顶部视图
            //获取顶部视图
            LTCollectionHeaderView *headerView = 
                [LTCollectionHeaderView headerViewWithCollectionView:collectionView
                                                        forIndexPath:indexPath];
            //设置顶部视图属性
            headerView.backgroundColor = [UIColor orangeColor];
            headerView.textLabel.text = [NSString stringWithFormat:@"-Header-%ld-",indexPath.section];
            return headerView;
            
        } else if( [kind isEqualToString:UICollectionElementKindSectionFooter] ) {//底部视图
            //获取底部视图
            LTCollectionFooterView *footerView = 
                 [LTCollectionFooterView footerViewWithCollectionView:collectionView
                                                         forIndexPath:indexPath];
            //设置底部视图属性
            footerView.backgroundColor = [UIColor greenColor];
            footerView.textLabel.text = [NSString stringWithFormat:@"-Footer-%ld-",indexPath.section];
            return footerView;
        }
        return nil;
    }
    4. UICollectionViewDelegateFlowLayout布局代理方法
    #pragma mark - UICollectionViewDelegateFlowLayout
    /* 设置各个方块的大小尺寸 */
    - (CGSize)collectionView:(UICollectionView *)collectionView
                      layout:(UICollectionViewLayout*)collectionViewLayout
      sizeForItemAtIndexPath:(NSIndexPath *)indexPath
    {
        CGFloat width = 50;
        CGFloat height = 50;
        return CGSizeMake(width, height);
    }
    /* 设置每一组的上下左右间距 */
    - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView
                            layout:(UICollectionViewLayout*)collectionViewLayout
            insetForSectionAtIndex:(NSInteger)section
    {
        return UIEdgeInsetsMake(10, 10, 10, 10);
    }
    5. 父协议UICollectionViewDelegate的代理方法
    #pragma mark - UICollectionViewDelegate
    /* 方块被选中会调用 */
    - (void)collectionView:(UICollectionView *)collectionView
            didSelectItemAtIndexPath:(NSIndexPath *)indexPath
    {
        NSLog(@"点击选择了第%ld组第%ld个方块",indexPath.section,indexPath.row);
    }
    /* 方块取消选中会调用 */
    - (void)collectionView:(UICollectionView *)collectionView
            didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
    {
        NSLog(@"取消选择第%ld组第%ld个方块",indexPath.section,indexPath.row);
    }
    @end
    效果图如下,左边为垂直滚动效果,右边为水平滚动效果

    如果修改下布局代理方法的上下左右边界距离:
    /* 设置每一组的上下左右间距 */
    - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView
                            layout:(UICollectionViewLayout*)collectionViewLayout
            insetForSectionAtIndex:(NSInteger)section
    {
        return UIEdgeInsetsMake(0, 0, 0, 0);
    }

     

  • 相关阅读:
    LeetCode(258):Add Digits
    LeetCode(7):Reverse Integer
    LeetCode(14):Longest Common Prefix
    LeetCode(58):Length of Last Word
    LeetCode(165): Compare Version Numbers
    LeetCode(20):Valid Parentheses
    LeetCode(125):Valid Palindrome
    Scala中Curring实战详解之Scala学习笔记-16
    Scala中SAM转换实战详解之Scala学习笔记-15
    Scala学习笔记-14
  • 原文地址:https://www.cnblogs.com/ming1025/p/6069390.html
Copyright © 2020-2023  润新知