美文网首页iOS
UICollectionView:详解

UICollectionView:详解

作者: 季舟1 | 来源:发表于2019-03-01 13:35 被阅读222次

    1. UICollectionView

    UICollectionView管理了一组有序的数据项(Data Item)集合,并使用自定义的层把它显示出来。


    当你添加了一个UICollectionView到你的用户界面后,你的APP的主要任务就是管理和这个UICollectionView相关联的数据(Data)。UICollectionView 从数据源中获取数据,这个数据源就是一个实现了UICollectionViewDataSource Protocol协议的对象。UICollectionView中的数据被组织成独特的项目,这些项目可以被分成不同的组,并展示出来。UICollectionView使用Cell来显示一个数据项(Data Item),这个Cell是一个UICollectionViewCell 的实例。

    除了Cell,UICollectionView还可以使用其他类型的视图来展示数据。这补充视图在头部和尾部区域展示一些有序的信息。补充视图由UICollectionView的布局(layout)对象定义,是可选项。这个布局(layout)对象同时负责视图的布置。

    除了需要在视图上展示这些Item,而且需要我们保证这些Item按照准确的序列展示。不管你是添加、删除还是重新排序这些Item,或者管理选择的Item。对于这些行为UICollectionView使用和其关联的委托(id<UICollectionViewDelegate> delegate;)对象。

    1.1. 概述

    1.1.1. 布局(layout)

    UICollectionView相关联的一个非常重要的对象就是布局(layout)对象,它是UICollectionViewLayout的一个之类。layout对象负责定义UICollectionView中所有单元格(Cell)和补充视图的组织和位置。虽然它定义了它们的位置,但layout对象实际上并不将这些信息应用于相应的视图。因为单元格和补充视图的创建涉及了UICollectionView和数据源对象之间的协调,所以实际上是UICollectionView将布局信息应用于视图。
    一般情况下是在创建UICollectionView时指定布局(layout),但是我们页可以动态改变布局(layout)。布局对象存储在UICollectionView 的collectionViewLayout property属性中。设置这个属性会立即修改布局没有动画效果。或者使用setCollectionViewLayout:animated:completion:方法可以设置动画效果。
    如果您想创建一个交互式的转换 :一种方法是由手势识别器或触摸事件驱动的转换,使用startInteractiveTransitionToCollectionViewLayout:completion:方法来更改布局对象。该方法安装一个中间布局对象,其目的是使用手势识别器或事件处理代码跟踪转换过程。当你的事件处理代码觉得转换已经完成时,它就调用finishInteractiveTransitioncancelInteractiveTransition方法来删除中间布局对象并安装预期的目标布局对象。

    1.1.2. 创建单元格和补充视图

    UICollectionView的数据源对象既提供项的内容,也提供用于表示该内容的视图。当UICollectionView首次加载其内容时,它要求其数据源为每个可见项提供一个视图。为了简化创建过程,UICollectionView要求对视图进行出列,而不是在代码中显式地创建视图。有两种方法可以出列视图:

    • 出列单元格视图
      dequeueReusableCellWithReuseIdentifier:forIndexPath:
    • 出列补充视图
      dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:

    在调用这两种方法之前,必须告诉UICollectionView,如果还不存在相应的视图,该如何创建相应的视图。为此,必须在collection视图UICollectionView中注册类或nib文件。例如,在注册单元格时,使用registerClass:forCellWithReuseIdentifier:registerNib:forCellWithReuseIdentifier:。作为注册过程的一部分,必须为视图指定可重用的标识符。在退出视图队列时使用的相同字符串。
    将委托方法中把适当的视图从队列中取出后,配置其内容并将其返回到UICollectionView中使用。然后从layout对象中获取布局信息,UICollectionView将其应用于视图并显示它。
    更详细信息见UICollectionViewDataSource

    1.1.3. 排序与交互

    UICollectionView允许用户移动单元格。通常UICollectionView中项的顺序是由数据源定义。如果支持用户重新排序项,则可以配置手势识别器来跟踪用户与视图项的交互,并更新该项的位置。
    调用UICollectionView的beginInteractiveMovementForItemAtIndexPath:方法,开始对一个视图进行重新排序交互;当手势识别器跟踪到触摸事件时,调用updateInteractiveMovementTargetPosition:方法,来报告触摸位置中的更改;当您完成跟踪手势时,调用endinteractivemomovementcancelinteractivemomovement方法来结束交互并更新集合视图。
    在用户交互期间,集合视图动态地使其布局失效,以反映项的当前位置。如果您什么都不做,默认的布局将重置项,您也可以自定义布局动画。当交互完成时,使用新的项位置更新其数据源对象。
    UICollectionViewController类提供了一个默认的手势识别器,可以使用它来重新排列视图中的项。要安装此手势识别器,将installsstandardgestureforinteractivemomotion属性设置为YES。

    1.2. UICollectionView

    1.2.1. 初始化

    - initWithFrame:collectionViewLayout:

    使用UICollectionViewLayout初始化。

    - initWithCoder:

    1.2.2. 提供数据源

    dataSource

    为CollectionView提供数据源

    UICollectionViewDataSource

    数据源协议,详见:https://www.jianshu.com/p/de5af0a36aa2

    UICollectionViewDataSourcePrefetching

    一种协议,它为CollectionView的数据需求提供预先的警告,允许触发异步数据加载操作。

    1.2.3. 管理交互

    delegate

    交互代理

    UICollectionViewDelegate

    交互代理协议,详见:https://www.jianshu.com/p/189c4b6c6935

    1.2.4. 定义背景视图

    backgroundView

    1.2.5. 预取视图单元格和数据

    UICollectionView提供了两种预抓取技术,您可以使用它们来提高响应能力。

    • Cell预取
      单元格预取是在需要单元格之前准备它们。默认开启。
    • Data预取
      在对单元格的请求之前通知CollectionView进行数据需求。如果单元格的内容依赖于耗时的数据加载过程(如网络请求),这将非常有用。将符合UICollectionViewDataSourcePrefetching协议的对象分配给prefetchDataSource属性,以接收何时预取单元格数据的通知。
      详见:https://www.jianshu.com/p/f8fd24415466
    prefetchingEnabled

    表示是否启用单元格和数据预取。

    prefetchDataSource

    CollectionView的预取数据源,接收单元格数据需求的通知。

    1.2.6. 创建视图单元格

    registerClass: forCellWithReuseIdentifier:

    注册一个类,用于创建新的集合视图单元格。

    - registerNib: forCellWithReuseIdentifier:

    注册一个nib文件,用于创建新的集合视图单元格。

    registerClass: forSupplementaryViewOfKind: withReuseIdentifier:

    注册一个类,用于为集合视图创建补充视图。

    - registerNib: forSupplementaryViewOfKind: withReuseIdentifier:

    注册一个nib文件,用于为集合视图创建补充视图。

    - dequeueReusableCellWithReuseIdentifier: forIndexPath:

    返回按其标识符定位的可重用单元格对象

    - dequeueReusableSupplementaryViewOfKind: withReuseIdentifier: forIndexPath:

    返回一个可重用的补充视图,该视图根据其标识符和类型定位。

    1.2.7. 调整布局

    collectionViewLayout

    CollectionView在使用的布局对象

    - setCollectionViewLayout:animated:

    改变布局

    - setCollectionViewLayout:animated:completion:

    改变布局

    - startInteractiveTransitionToCollectionViewLayout:completion:

    使用交互转换效果更改CollectionView的布局

    - finishInteractiveTransition

    完成交互转换效果更改布局

    - cancelInteractiveTransition

    取消交互转换效果更改布局

    1.2.8. 获取状态

    numberOfSections

    返回Section的数量。

    - numberOfItemsInSection:

    返回指定Section的Cell的数量。

    visibleCells

    返回所有可见Cell的数组。

    1.2.9. 增加、删除和移动项目

    - insertItemsAtIndexPaths:

    在指定的位置插入新项

    - moveItemAtIndexPath:toIndexPath:

    移动项

    - deleteItemsAtIndexPaths:

    删除项

    1.2.10. 增加、删除和移动区域

    - insertSections:

    添加区域

    - moveSection:toSection:

    移动区域

    - deleteSections:

    删除区域

    1.2.11 重新排序交互

    - beginInteractiveMovementForItemAtIndexPath:

    在某一个Cell上(由IndexPath参数指定)开始移动交互。
    当您想要把同一CollectionView中的一个项从当前位置移动到新位置时,就调用此方法。使用手势识别器跟踪项目的移动,当手势识别开始时,调用此方法。当结束交互时,您必须调用endinteractivemomovementcancelinteractivemomovement方法来通知CollectionView。当您调用此方法时,CollectionView将咨询delegate以确保是否可以移动项。如果数据源不支持移动,则此方法返回NO。

    - updateInteractiveMovementTargetPosition:

    在移动一个项时, 使用此方法向CollectionView提供项的新位置。 当使用手势识别器跟踪用户与项的交互时,每当手势识别器报告位置更改时调用此方法。CollectionView使用新点来确定是否需要重新定位项,以及是否需要更新当前布局。对于每个位置的更改,CollectionView将该更改报告给collectionView:targetIndexPathForMoveFromItemAtIndexPath:toProposedIndexPath:

    - endInteractiveMovement

    在跟踪项移动完成后调用此方法。例如,当使用手势识别器跟踪用户交互时,在手势成功完成时调用此方法。调用此方法可以让CollectionView知道终止跟踪并将项永久移动到其新位置。CollectionView通过调用collectionView:moveItemAtIndexPath:toIndexPath: 方法来响应,以确保更新了数据结构。

    - cancelInteractiveMovement

    调用此方法取消移动跟踪并将项目返回到其原始位置。例如,当使用手势识别器跟踪交互时,在取消手势时调用此方法。调用此方法可以让集合视图知道结束跟踪过程并将项返回到其原始位置。

    1.2.12. 管理拖拽交互

    dragDelegate

    拖动委托对象

    UICollectionViewDragDelegate

    详见:https://www.jianshu.com/p/4211eee0993d

    hasActiveDrag

    一个布尔值,指示项是否已从集合视图中移除且尚未被删除。

    dragInteractionEnabled

    是否支持拖拽删除交互

    1.2.13. 管理删除交互

    dropDelegate

    管理将项放入集合视图的委托对象。

    hasActiveDrop

    一个布尔值,指示集合视图当前是否跟踪删除会话。

    reorderingCadence

    重新排序集合视图中的项以显示潜在的删除位置的速度。

    UICollectionViewReorderingCadence

    常量,指示在删除期间重新组织集合视图项的速度。

    1.2.14. 管理选择

    allowsSelection

    是否可以选择

    allowsMultipleSelection

    是否可以多选

    indexPathsForSelectedItems

    返回选定项目的数组

    - selectItemAtIndexPath:animated:scrollPosition:

    选定指定的项目

    - deselectItemAtIndexPath:animated:

    取消选定指定的项目

    1.2.15. 管理焦点

    1.2.16. 定位项目和视图

    - indexPathForItemAtPoint:

    根据Point返回CollectionView中对应Item的IndexPath。

    indexPathsForVisibleItems

    返回所有可见Item。

    - indexPathForCell:

    根据Cell返回CollectionView中对应Item的IndexPath。

    - cellForItemAtIndexPath:

    根据IndexPath返回CollectionView中对应Item的Cell。

    - indexPathsForVisibleSupplementaryElementsOfKind:

    根据指定类型返回所有可见附加视图的IndexPath。

    - supplementaryViewForElementKind:atIndexPath:

    根据IndexPath返回附加视图。

    - visibleSupplementaryViewsOfKind:

    根据指定类型返回所有可见附加视图。

    1.2.17. 获取Layout信息

    - layoutAttributesForItemAtIndexPath:

    返回指定IndexPath上Item的布局信息。

    - layoutAttributesForSupplementaryElementOfKind:

    返回指定补充视图的布局信息。

    1.2.18. 把项目在视图中显示

    1.2.19. 动态展示多选修改

    1.2.20. 重新加载内容

    hasUncommittedUpdates

    一个布尔值,指示集合视图是否包含删除占位符或作为处理删除的一部分重新排序其项。

    -reloadData

    重新加载集合视图的所有数据。

    - reloadSections:

    在集合视图的指定部分重新加载数据。

    - reloadItemsAtIndexPaths:

    仅在指定索引路径上重新加载项。

    1.2.21. 常数

    2. UICollectionViewDataSource

    采用UICollectionViewDataSource协议的对象负责提供集合视图所需的数据和视图。数据源对象表示APP的数据模型,并向UICollectionView提供信息。它还处理创建和配置单元格和补充视图。
    UICollectionViewDataSource必须实现collectionView:numberOfItemsInSection:collectionView:cellForItemAtIndexPath:。这些方法负责返回集合视图中的项数以及项本身。协议的其余方法是可选的,只有当集合视图将项组织成多个节,或者为给定节提供页眉和页脚时,才需要这些方法。
    在配置集合视图对象时,将数据源分配给它的dataSource属性。有关集合视图如何使用其数据源显示内容的更多信息,请参见UICollectionView。

    2.1.1. 获取section和item的大小

    2.1.2. 获取item的视图

    2.1.3. item排序

    2.1.4. 配置索引

    1.1. numberOfItemsInSection

    必须要实现的方法,返回的值是在每一个分组(分区)中包含的单元格的个数。

    - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section;
    
    1.2. cellForItemAtIndexPath

    必须要实现的方法,返回的值是在每一个分组(分区)中包含的在每一个位置的单元格的内容,并且必须是使用dequeuereusablecellwithreuseidentifier方法中找出重用单元格。

    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;
    
    1.3. numberOfSectionsInCollectionView

    不是必须要实现的方法,返回的值是一个collectionView中的分组(分区)个数。我们自己不实现的话,系统默认返回值为1。

    - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView;
    
    1.4. viewForSupplementaryElementOfKind

    不是必须要实现的方法,返回的值是collectionView中的分组(分区)的头部试图view或者尾部视图view。我们自己不实现的话,系统默认返回值为nil。

    - (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;
    
    1.5. canMoveItemAtIndexPath

    不是必须要实现的方法,询问是否指定的单元格项目是否可以移动到集合视图中的另一个位置,默认返回值为NO。

    - (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(9_0);
    
    1.6. moveItemAtIndexPath

    不是必须要实现的方法,将指定的单元格项目从一个位置移动到集合视图中的另一个位置。

    - (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath*)destinationIndexPath NS_AVAILABLE_IOS(9_0);
    

    2、UICollectionViewDelegate

    UICollectionViewDelegate中的协议方法全都不是必须要实现的,我们自己选择是否实现。

    1.1. 三个和高亮有关的方法
    - (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath
    - (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath
    - (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath
    

    事件的处理顺序如下:

    1. 手指按下:shouldHighlightItemAtIndexPath (如果返回YES则向下执行,否则执行到这里为止)
    2. didHighlightItemAtIndexPath (高亮)
    3. 手指松开:didUnhighlightItemAtIndexPath (取消高亮)
    4. shouldSelectItemAtIndexPath (如果返回YES则向下执行,否则执行到这里为止)
    5. didSelectItemAtIndexPath (执行选择事件)
      如果只是简单实现点击后cell改变显示状态,只需要在cellForItemAtIndexPath方法里返回cell时,指定cell的selectedBackgroundView;如果要实现点击时(手指未松开)的显示状态与点击后(手指松开)的显示状态,则需要通过上面提到的方法来实现。
    1.2.

    当指定indexPath处的item被选择时触发,调用该方法

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

    当指定indexPath处的item被取消选择时触发,仅在允许多选时被调用

    - (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath;
    
    1.4.

    这两个方法分别是指定indexPath的cell将要显示出的时候调用和指定indexPath的头部或尾部视图view将要显示出来的时候调用

    - (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0);
    - (void)collectionView:(UICollectionView *)collectionView willDisplaySupplementaryView:(UICollectionReusableView *)view forElementKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0);
    
    1.5.

    这两个方法分别是指定indexPath的cell将要从collectionView中移除的的时候调用和指定indexPath的头部或尾部视图view将要collectionView中移除的时候调用

    - (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath;
    - (void)collectionView:(UICollectionView *)collectionView didEndDisplayingSupplementaryView:(UICollectionReusableView *)view forElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath;
    

    A. DEMO

    A.1. 多选

    1. 设置Collection View的属性允许多选
        // 允许多选
        _collectionView.allowsMultipleSelection=YES;
    
    1. 添加选择和取消选择方法
    - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
        NSLog(@"点击cell %@",indexPath);
        SimpleCollectionViewCell * cell = (SimpleCollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath];
        cell.titleLabel.textColor =[UIColor whiteColor];
        cell.backgroundColor=[UIColor greenColor];
    }
    
    - (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath{
        NSLog(@"取消cell %@",indexPath);
        SimpleCollectionViewCell * cell = (SimpleCollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath];
        cell.titleLabel.textColor =[UIColor redColor];
        cell.backgroundColor=[UIColor grayColor];
    }
    
    1. 获取选择Index
    -(void)showSelected{
        NSArray<NSIndexPath *> * selectedItems=_collectionView.indexPathsForSelectedItems;
        for (NSIndexPath *selectedItem in selectedItems) {
            NSLog(@"item index:###%ld",selectedItem.item);
        }
    }
    
    代码

    https://github.com/DavidJi80/iosCodeUI
    v0.7.2

    参考
    https://developer.apple.com/documentation/uikit/uicollectionview?language=objc
    https://www.jianshu.com/p/6f5b834de1e5
    https://www.jianshu.com/p/34e3d23ee26f
    多选
    https://blog.csdn.net/iotjin/article/details/80137427
    动态添加
    https://www.jianshu.com/p/770ab0e75af2
    https://www.jianshu.com/p/32ee3e78b80e

    相关文章

      网友评论

        本文标题:UICollectionView:详解

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