理解 UICollection Flow Layout 流式布局

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了理解 UICollection Flow Layout 流式布局相关的知识,希望对你有一定的参考价值。

参考技术A

UICollectionView 因为 流式布局 (flow layout)而成了为一个非常强大的 UI 组件,流式布局是一种动态网格,提供了 table view 所不具备的功能。

flow layout 实际上是 layout 的子类。(普通的)layout 要更强大一点,因为你可以任意布局单元格!环形布局?没问题!

但在本文中,我们只讨论垂直的流式布局。

有两种实现方式:

在讨论如何实现上面的方法之前,先搞懂单元格是如何被布局的。

用垂直的流式布局作为例子(水平的很相似)。

如果单元格具有固定的大小,只要使用 layout 对象即可—— [UICollectionViewFlowLayout](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UICollectionViewFlowLayout_class/index.html#//apple_ref/occ/instp/UICollectionViewFlowLayout/)

这是单元格为 100x100 的例子,相隔 至少 8pt,section inset 也为 8pt。

如果单元格很简单,布局就这么简单。

如果单元格有不同的尺寸,就需要用高级方法了,要实现 [UICollectionViewDelegateFlowLayout](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UICollectionViewDelegateFlowLayout_protocol/#//apple_ref/occ/intfm/UICollectionViewDelegateFlowLayout/) 。

使用了相同的 UICollectionViewFlowLayout 对象,但会实现它的代理方法以定制更高级的功能。

举个例子,如果每个单元格尺寸不同,会实现如下方法:

对于最小行间距、单元格间距等等都有对应的代理方法。

这些都是可选的,如果不实现它们,就会直接使用流式布局对象的属性。

一个 常见问题 是要让单元格有 固定的间距

然而,只能设置 minimumInteritemSpacing ,实际单元格间距由 collection view 的宽度决定。

UICollectionViewFlowLayout 会在应用 section inset 后排列中间的单元格,每个单元格之间的间距都相同。

如果想要固定的间距, 这么做 可以实现,通过修改 section 的左右 inset:

流式布局是开箱即用的。易于使用,对于大多数 UI 都足够了。

但也可以创建自己的 自定义布局 。

布局类的核心方法是 layoutAttributesForElementsInRect: 。可以读一下 来自 objc.io 的教程,写的很好。这是更高级别的主题。

注意: 通常我们会使用 autolayout 约束,但对于单元格(cell),需要用传统的方式设置 frame。只有 cell 要这么做。单元格里面的视图仍然可以使用自动布局。

UICollection 的镜像滚动

【中文标题】UICollection 的镜像滚动【英文标题】:Mirror scrolling of UICollection 【发布时间】:2013-04-10 05:32:47 【问题描述】:

我创建了一个具有自定义布局的 UICollection,以允许垂直和水平滚动。它是一个由相等部分和每个部分中的项目组成的网格(即 10 x 10、20 x 20 等)。我希望能够放置两个仍然可见的标题,一个在顶部,一个在左侧。我还没有找到在 UICollection 本身中执行此操作的方法。因此,我在左侧设置了 UICollection,在顶部设置了另一个。但是,当用户左右和/或上下滚动网格时,我希望这两个集合能够反映这些移动。

所以,我的问题是:有没有办法将主 UICollection 的水平移动镜像到顶部 UICollection,然后将主 UICollection 的垂直移动镜像到侧面 UICollection?

谢谢!

【问题讨论】:

【参考方案1】:

UICollectionViewUIScrollView 的子类。它向其委托发送UIScrollViewDelegate protocol 中定义的所有消息。

您要回复的消息是scrollViewDidScroll:。当您的主集合视图发送此消息时,您希望通过获取其contentOffset 并将偏移量应用于您的边距集合视图来响应它。

// Implement this in your main collection view's delegate.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView 
    [self synchronizeCollectionViewContentOffsets];


- (void)synchronizeCollectionViewContentOffsets 
    CGPoint offset = self.mainCollectionView.contentOffset;
    self.leftMarginView.contentOffset = CGPointMake(0, offset.y);
    self.topMarginView.contentOffset = CGPointMake(offset.x, 0);

【讨论】:

当视图首次显示时,它会自动滚动到主 UICollectionView 中的特定单元格,这确实会触发 scrollViewDidScroll 方法,然后触发 synchronize 方法;然而,在第一行创建的偏移点基本上是 0,0,即使它滚动到的点甚至不接近那个点。当我尝试滚动网格时也是这种情况。创建的偏移点始终为 1.343243x-34 或类似的值。【参考方案2】:

所以,我想通了。使用 self.mainCollectionView.contentOffset 总是返回 (0,0),所以尝试使用我通过 Storyboard 和视图控制器实际分配给它的对象名称。这行得通。

-(void)scrollViewDidScroll:(UIScrollView *)scrollView 
    [self synchronizeCollectionViewContentOffsets];


-(void)synchronizeCollectionViewContentOffsets 
    CGPoint offset = myCollectionView.contentOffset;
    myLeftMargin.contentOffset = CGPointMake(0, offset.y);
    myTopMargin.contentOffset = CGPointMake(offset.x, 0);

myCollectionView、myLeftMargin 和 myTopMargin 通过 Storyboard 链接到 UICollectionView。

【讨论】:

以上是关于理解 UICollection Flow Layout 流式布局的主要内容,如果未能解决你的问题,请参考以下文章

4.UiCollection API 详细介绍

在单独的 UICollection 类中使用未解析的标识符“UICollection”

UICollection 的镜像滚动

视频库的UICollection

深入理解Kotlin协程协程中的Channel和Flow & 协程中的线程安全问题

UICollection 单元格快速混合