UICollectionView的简单介绍
UICollectionView的结构
Cells
Supplementary Views 追加视图 (类似Header或者Footer)
Decoration Views 装饰视图 (用作背景展示)
由两个方面对UICollectionView进行支持
和tableView一样,即提供数据的UICollectionViewDataSource以及处理用户交互的UICollectionViewDelegate。
另一方面 对于cell的样式和组织方式,由于collectionView比tableView要复杂得多,因此没有按照类似于tableView的style的方式来定义,而是专门使用了一个类来对collectionView的布局和行为进行描述,这就是UICollectionViewLayout
而我们主要讲UICollectionViewLayout,因为这不仅是collectionView和tableView的最重要求的区别,也是整个UICollectionView的精髓所在
UICollectionViewLayoutAttributes类的介绍
一个UICollectionViewLayoutAttributes
对象管理着一个Collection View
中给定的一个Item的布局有关的属性。当被CollectionView要求时布局对象创建这个类的实例。
open class UICollectionViewLayoutAttributes : NSObject, NSCopying, UIDynamicItem { open var frame: CGRect item的位置 open var center: CGPoint item的中心点 这个中心点是在给定的Collection View
坐标系中的点。设置这个属性的值也会更新frame
属性中的origin
的值。 open var size: CGSize item的大小 open var transform3D: CATransform3D item的放射变化 使用你指定的放射变换赋值给这个属性替换transform3D
属性的值 @available(iOS 7.0, *) open var bounds: CGRect @available(iOS 7.0, *) open var transform: CGAffineTransform item在平面上的变化 open var alpha: CGFloat item的透明度 0 - 1 open var zIndex: Int // default is 0 item指定在Z轴上的位置 这个属性被用来确定在布局时Item的前后顺序。大的zIndex
值的Item会被显示在小的zIndex
值的Item上面。这个属性使用相同的值的Item的顺序是不确定的。
这个属性的值默认为0
open var isHidden: Bool // As an optimization, UICollectionView might not create a view for items whose hidden attribute is YES open var indexPath: IndexPathCollection View
中Item的索引值。
索引包含了一个Section的索引和一个Item在这个Section中的索引。这两个值标示在Collection View
唯一的对应的Item的位置。open var representedElementCategory: UICollectionElementCategory { get } Item的类型。
你可以使用这个属性的值来区分这个布局属性是用于一个Cell还是Supplementary View还是Decoration View。 open var representedElementKind: String? { get } // nil when representedElementCategory is UICollectionElementCategoryCell
你可以使用这个属性的值来标识 Supplementary View或者 Decoration View相关联的 属性给定的目的。如果
representedElementCategory
属性为
UICollectionElementCategoryCell
,那么这个 属性为
nil
。
}
typedef NS_ENUM(NSUInteger, UICollectionElementCategory) {
UICollectionElementCategoryCell, // Cell
UICollectionElementCategorySupplementaryView, // Supplementary View
UICollectionElementCategoryDecorationView // Decoration View
};
自定义UICollectionViewLayout
UICollectionViewLayout的功能是向UICollectionView提供布局信息 不仅包括cell的布局信息,也包括追加视图和装饰视图的布局信息。实现一个自定义layout的常规做法是继承UICollectionViewLayout类,然后重载下列方法:
准备方法被自动调用 以保证layout实例的正确 为即将进行的layout作前期的计算
open func prepare()
返回指定区域中的Cell和View的属性
返回的是包含UICollectionViewLayoutAttributes的数组 UICollectionViewLayoutAttributes可以是数组 追加视图(头尾视图)的信息
func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]?
返回对应于indexPath的位置的cell的布局属性
func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes?
返回对应于indexPath的位置的追加视图的布局属性,如果没有追加视图可不重载
使用这个方法为
Collection View
中的一个
Supplementary View创建一个布局属性对象。和
Cell一样,
Supplementary View当前的数据是被
Collection View
数据源所管理的。但是和
Cell不同的是,
Supplementary View通常是为特殊目的而设计的。例如,
Header和
Footer与
Cell的放置位置不同,是提供给在单个的
Section或者整个
Collection View
的。
由你来决定如何使用
indexPath
参数来识别一个给定的
Supplementary View。通常,你使用
elementKind
属性来确定
Supplementary View的类型,然后使用
indexPath
的信息来识别不同
Supplementary View实例。
func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes?
使用这个方法为
Collection View
中的一个
Decoration View创建一个布局属性对象。
Decoration View是
Supplementary View的一种,但是不会展示被
Collection View
数据源所管理的数据。相反,它们大多数为一个
Section或者整个
Collection View
呈现视觉装饰效果。
由你来决定如何使用
indexPath
参数来识别一个给定的
Decoration View。通常,你使用
decorationViewKind
属性来确定
Decoration View的类型,然后使用
indexPath
的信息来识别不同
Decoration View实例。
func layoutAttributesForDecorationView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes?
当边界发生改变的时候 是否应该刷新布局 如果YES则在边界变化(一般是scroll到其他地方)时,将重新计算需要的布局信息。
func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool
方法的调用顺序
1)-(void)prepareLayout 设置layout的结构和初始需要的参数等。
2) -(CGSize) collectionViewContentSize 确定collectionView的所有内容的尺寸。
3)-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect初始的layout的外观将由该方法返回的UICollectionViewLayoutAttributes来决定。
4)在需要更新layout时,需要给当前layout发送
1)-invalidateLayout, 该消息会立即返回,并且预约在下一个loop的时候刷新当前layout
2)-prepareLayout,
3)依次再调用-collectionViewContentSize和-layoutAttributesForElementsInRect来生成更新后的布局。