Using the Flow Layout
你可以在collection view中使用UICollectionViewFlowLayout类来组织item。Flow layout实现了一个基于线的布局,就是说布局对象在一条线性路径尽可能多的放置cell。当布局对象到达了当前行的末尾是,会另起一行。
配置flow layout的步骤:
- 创建一个flow layout对象,并把它指派给collection view
- 配置cell色高度和宽度
- 设置line和item的space
- 如果你需要section headers或者section footers,指定它们的大小。
- 设置layout滑动的方向
自定义Flow Layout的属性(Customizing the Flow Layout Attributes)
例如可以使用itemSize属性来设置cell的大小。
如果你想动态的变化item的spacing或者size,你可以使用UICollectionViewDelegateFlowLayout协议。
在Flow Layout指定Item的大小
如果collection view中的item都是同样的大小,可以通过flow layout对象的itemSize
属性来指定长宽。
如果你想为cell指定不同的大小,你需实现collection view代理的collectionView:layout:sizeForItemAtIndexPath:
方法。
指定Items 和 Lines间的间隔
使用flow layout,你可以指定同一行item之间的间隔,也可以指定连续行之间的最小空间大小。要记住的是,你提供的只是最小间隔(minimum spacing)。
你可以使用 flow layout对象的minimumLineSpacing和minimumInteritemSpacing属性来指定间隔大小,也可以使用代理方法collectionView:layout:minimumLineSpacingForSectionAtIndex:和collectionView:layout:minimumInteritemSpacingForSectionAtIndex:来指定间隔大小。
使用Section Inset来调整内容的间距
由于inset减少了布局cell所用的空间,你可以使用它们来限制一行的cell数量。
创建自定义布局(Creating Custom Layouts)
理解布局的过程(Understanding the Core Layout Process)
当collection view 需要布局信息的时候,它会请求布局对象提供信息。你可以调用invalidateLayout
方法来告诉collection view更新它的布局。
在布局的工程中,collection view 会调用特定的方法。这些方法可以计算item的位置,和提供给collection view所需的信息。其它的方法也可能会被调用,这些方法在布局的工程中调用的顺序如下:
- 使用prepareLayout方法预先计算需要提供给布局的信息
- 使用collectionViewContentSize方法,返回根据你初步计算的整个内容区域的整体尺寸
- 使用layoutAttributesForElementsInRect:方法,返回在指定区域的cell和view的属性。
prepareLayout来计算cell和view在布局中位置。至少,你应该要得到content area的大小,这是在step2中返回给collection view的。
collection view使用这个content size来配置scroll view。例如,如果计算的大小在水平和垂直方向超过了当前设备屏幕的大小,那么scroll view就可以在两个方向上滚动。
基于当前滚动的位置,collection view会调用layoutAttributesForElementsInRect:方法来获取在特定区域的cell和view的属性。
在滚动的过程中,collection view可以使你当前的布局无效。用户滑动时,collection view调用布局对象的shouldInvalidateLayoutForBoundsChange:方法,如果这个方法返回YES,则会使当前的布局无效。
创建布局属性Creating Layout Attributes
布局的属性对象是UICollectionViewLayoutAttributes类。使用如下的方法来创建UICollectionViewLayoutAttributes类的实例:
- layoutAttributesForCellWithIndexPath:
- layoutAttributesForSupplementaryViewOfKind:withIndexPath:
- layoutAttributesForDecorationViewOfKind:withIndexPath:
按需求提供布局属性
- layoutAttributesForItemAtIndexPath:
- layoutAttributesForSupplementaryViewOfKind:atIndexPath:
- layoutAttributesForDecorationViewOfKind:atIndexPath:
使用自定义的布局
self.collectionView.collectionViewLayout = [[MyCustomLayout alloc] init];
使自定义布局更吸引人
Elevating Content Through Supplementary Views
所有的supplementary view都必须继承自UICollectionReusableView 类:
- 注册supplementary view,使用registerClass:forSupplementaryViewOfKind:withReuseIdentifier:或者 registerNib:forSupplementaryViewOfKind:withReuseIdentifier:方法
- 在data source中,实现collectionView:viewForSupplementaryElementOfKind:atIndexPath:方法。因为这些view是复用的,调用dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:方法来复用。
- 为supplementary view创建布局属性对象
- 在layoutAttributesForElementsInRect:方法中返回属性数组
- 实现layoutAttributesForSupplementaryViewOfKind:atIndexPath:方法来特定的supplementary view 的属性对象
Including Decoration Views in Your Custom Layouts
与cells和supplementary view不同,decoration view只提供visual content,并独立于data source之外。
添加decoration view到布局中,按如下的方式:
- 使用布局对象的registerClass:forDecorationViewOfKind: 或者registerNib:forDecorationViewOfKind: 方法来注册 decoration view。要记住的是,注册decoration view是在布局对象内,而不是在data source
- 在布局对象的layoutAttributesForElementsInRect: 方法中创建属性
- 在布局对象中实现layoutAttributesForDecorationViewOfKind:atIndexPath:方法,返回decoration views的属性
- 可选,实现initialLayoutAttributesForAppearingDecorationElementOfKind:atIndexPath:和finalLayoutAttributesForDisappearingDecorationElementOfKind:atIndexPath:方法来处理decoration view出现和消失的动画。
Making Insertion and Deletion Animations More Interesting
如下图所示,collection view起初只有3个cell。当一个新的cell被插入时,collection view请求布局对象提供被插入cell的初始属性。在这个例子中,布局对象把cell的初始位置设置为collection view的中心,并把cell的alpha值设为0,来隐藏它。在动画的过程中,新的cell慢慢出现并移动到右下角。
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath {
UICollectionViewLayoutAttributes* attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];
attributes.alpha = 0.0;
CGSize size = [self collectionView].frame.size;
attributes.center = CGPointMake(size.width / 2.0, size.height / 2.0);
return attributes;
}
Note:上面的代码中,当一个cell插入时,所有的cell,即3个已经展示的cell都会从collection view的中间pop out ,当第四个cell插入的时候。为了仅仅使被插入的cell动画,应当查看item的indexPath是否与prepareForCollectionViewUpdates:方法中传递的item的indexPath是否匹配。否者的话,在initialLayoutAttributesForAppearingItemAtIndexPath:中调用super方法。
Improving the Scrolling Experience of Your Layout
当滚动相关的触摸事件发生时,scroll view会通过当前的speed和减速度来,决定最后的位置。当collection view明确了位置,它会请求调用布局对象的targetContentOffsetForProposedContentOffset:withScrollingVelocity: 方法来确定是否修改位置。因为它调用这个方法的时候,内容还在移动,所以你的自定义的布局能够影响滚动内容的最终位置。
使用自定义布局Tips
- 使用prepareLayout方法来创建和存储UICollectionViewLayoutAttributes对象。
- 避免继承UICollectionView
- 一定不能在layoutAttributesForElementsInRect:方法中调用UICollectionView的visibleCells 方法。
参考教程
- TUTORIAL: Creating custom layouts for UICollectionView
- TUTORIAL: Using UICollectionView with UICollectionViewFlowLayout
- Implementing UICollectionViewLayout
- UICollectionView custom layout tutorial
- WWDC 2012 Session笔记——219 Advanced Collection Views and Building Custom Layouts
- WWDC 2012 Session笔记——205 Introducing Collection Views