iOS Collection View 编程指导(三)-如何使用Flow Layout

UICollectionViewFlowLayout类来管理collectionView中的布局, 它是一个具体的类, 可以直接使用. flow layout实现了一种基于线性的断裂式布局, 也就是说collectionView中的item是按照线性顺序排列的, 该布局会尽量适配item的间距, 使得item排列在同一行, 如果超出一行会接着进行下一行的排列. 图3-1展示了水平方向上的flow layout.

iOS Collection View 编程指导(三)-如何使用Flow Layout_第1张图片
图3-1 使用flow layout布局section和cell

使用flow layout除了可以实现一个网格状的collectionView, 还可以实现更多样式. 比如, 你可以调整间距来实现一个单行滚动的collectionView. 如果item的size可以不同, 这样可以产生非对称效果. 你可以通过代码和xib来配置你的flow layout对象, 步骤如下:

  • 创建一个flow layout对象, 将其赋值给collectionView
  • 设置cell的width和height
  • 设置行间距, item的间距
  • 如果你想要section header和footer, 给footer和header设置size
  • 设置flow layout滚动的方向(scroll layout)

注意:配置layout时, 你至少需要配置cell的宽高, 不然item默认的宽高为0, 导致item不可见

自定义Flow Layout Attributes


flow layout对象暴露了几个属性用于配置item的外观, 当你设置这些属性时, 该属性对所有的item都有起作用. 比如你通过属性itemSize来配置item的大小后, 所有的item大小都和属性中配置的一样.

如果你想item的size和spacing都不一样, 那么你需要实现flow layout的委托UICollectionViewDelegateFlowLayout. 你可以将collectionView的delegate和flow layout的delegate设置成同一个. 当flow layout的delegate实现了相应的方法后, layout对象根据你实现的方法中返回的值来设置item的size和spacing.

设置item的size

  • 如果collectionView中的cell大小相同, 那么flow layout中的item的size大小可以通过itemSize来确定.
  • 如果item的size要不同, 那么需要实现委托方法collectionView:layout:sizeForItemAtIndexPath:来确定不同item的size. 在委托方法中, 你可以根据index path来确定不同item, 从而确定特定item的size. 如图3-2展示了不同item的不同size
iOS Collection View 编程指导(三)-如何使用Flow Layout_第2张图片
图3-2 flow layout中的不同itemSize

注意:如果item的size是不同的, 那么会导致不同行的item的数量不同

设置行间距和itme的间距

  • 使用flow layout布局时, 你可以设置item间的最小间距, 以及最小行间距. 需要注意, 是最小间距, 而不是具体的间距, 也就是说实际显示的间距可能和你设置最小间距不同, 有可能大于最小间距.
  • 在布局时, flow layout往一行中加item, 直到一行显示不下, 才开始第二行. 如果一行刚好可以显示整数个item没有额外的空间, 那么此时item的间距为最小间距. 若果还有额外的空间, 那么layout对象会将item的间距均匀地调大以刚好适配屏幕. 如图3-3所展示调整itme的间距来避免最后留下大块空间
iOS Collection View 编程指导(三)-如何使用Flow Layout_第3张图片
图3-3 item的实际间距大于最小间距
  • 对于行间距, flow layout使用同样原理来管理. 而且当item的size不同时, 导致行间距也不同. 行间距的实际距离和相邻两行中最大的两个item有关, 如图3-4所示


    iOS Collection View 编程指导(三)-如何使用Flow Layout_第4张图片
    图3-4 不同itemSize时的行间距
  • flow layout提供两个属性minimumLineSpacingminimumInterItemSpacing来设置静态的行间距和item间距, 如果想动态提供行间距和item间距可以使用委托方法collectionView:layout:minimumLineSpacingForSectionAtIndex:collectionView:layout:minimumInteritemSpacingForSectionAtIndex:来提供动态的间距.

使用Section Insets来调节section的margin

section inset是调节cells使用空间的一种手段. 你可以在section的左右, header/footer上下之间插入间距达到调节cell布局的空间大小. 如图3-5所示, 展示section inset的作用.


iOS Collection View 编程指导(三)-如何使用Flow Layout_第5张图片
图3-5 section inset调节cell的可用空间

什么时候使用子类化的Flow Layout


在有的情况下, 使用UICollectionViewFlowLayout满足不了需求, 需要继承UICollectionViewFlowLayout做一些定制化的操作才行. 下面列举了使用子类化UICollectionViewFlowLayout的几种情况:

  • 给你的布局添加新的补充视图(supplementary)和装饰视图(decoration)

    标准的flow layout只提供了header, footer没有decoration view, 为了支持更多的supplementary和decoration view你需要重写下面的一些方法:

    • layoutAttributesForElementsInRect:(required)
    • layoutAttributesForItemAtIndexPath:(required)
    • layoutAttributesForSupplementaryViewOfKind:atIndexPath:(为了支持新的supplementary视图)
    • layoutAttributesForDecorationViewOfKind:atIndexPath:(为了支持新的decoration视图)
      layoutAttributesForElementsInRect:方法中, 需要调用父类方法来获得cell的layout attribute对象, 然后再添加supplementary或者decoration的layout attribute对象. 再使用其他方法来提供其他attribute. 关于如何创建layout attribute请看Creating Layout Attributes
  • 给flow layout返回的layout attribute对象做点调整

    重写layoutAttributesForElementsInRect:方法以及其他返回layout attribute对象的方法. 在这些方法中你应该调用super来获取attribute对象, 在方法中修改调用super获取layout attribute对象, 然后返回.

  • 给cell和其他view替换新的layout attribute对象

    • 通过集成UICollectionViewLayoutAttributes类, 自定义layout attribute对象, 你可以往layout attribute中添加新的特性(属性).
    • 然后在UICollectionViewFlowLayout的子类重写layoutAttributesClass方法返回你自定义的UICollectionViewLayoutAttributes的子类.
    • 你还应该重写layoutAttributesForElementsInRect:,layoutAttributesForItemAtIndexPath:方法, 在这些方法中你要给新的layout attribute对象中属性赋值.
  • 插入/删除的item, 确定item的initial/final位置

    默认情况下, 当你插入/删除cell时, 只有一个fade动画, 如果你想要自定义动画, 可以重写下面的方法:

    • initialLayoutAttributesForAppearingItemAtIndexPath:
    • initialLayoutAttributesForAppearingSupplementaryElementOfKind:atIndexPath:
    • initialLayoutAttributesForAppearingDecorationElementOfKind:atIndexPath:
    • finalLayoutAttributesForDisappearingItemAtIndexPath:
    • finalLayoutAttributesForDisappearingSupplementaryElementOfKind:atIndexPath:
    • finalLayoutAttributesForDisappearingDecorationElementOfKind:atIndexPath:
      在cell被插入/删除前, 你可以通过上面的方法来设置特定的layout attribute对象, 然后flow layout会使用这些attribute来进行动画. 如果你重写了这些方法, Apple推荐你也重写prepareForCollectionViewUpdates:finalizeCollectionViewUpdates这两个方法. 你可以使用者两个方法来跟踪当前周期内那个item被插入/删除. 想知道关于删除/插入的工作原理, 请看Making Insertion and Deletion Animations More Interesting

上面的几种情况和操作也适用于创建自定义的layout, 不过在自定义layout之前考虑一下是否可以使用子类化的flow layout, 如果可以的话, 建议优先使用flow layout的子类, 因为flow layout是经过苹果精心设计的, 效果更好. 事实上, 需要用到自定义layout的情况很少, 因为使用flow layout或继承flow layout可以满足大多数需求. 只有少数情况下才需要自定义layout, 比如, 你的布局不是基于线性的, 或者你的内容不局限在屏幕两个方向上滚动, 你布局中的item经常移动, 在这些情况下用自定义layout更好点.

你可能感兴趣的:(iOS Collection View 编程指导(三)-如何使用Flow Layout)