目錄
項目下載地址: CollectionView-Note
UICollectionView 01 - 基礎布局篇
UICollectionView 02 - 布局和代理篇
UICollectionView 03 - 自定義布局原理篇
UICollectionView 04 - 卡片布局
UICollectionView 05 - 可伸縮Header
UICollectionView 06 - 瀑布流布局
UICollectionView 07 - 標簽布局
我們在使用系統(tǒng)的 UICollectionViewFlowLayout 時,只需要告訴它元素大小、間距、滾動方向之類的就能看到一個流式布局,那是因為它根據(jù)我們提供的信息,幫我們計算了每個元素的布局信息。這個布局信息存放在 UICollectionViewLayoutAttributes 。 所以如果我們自定義布局的時候這些就需要我們自己計算,然后計算完最好緩存起來避免重復計算,然后在界面需要展示的時候把這個信息傳遞過去。 當然我們的自定義布局可以基于 UICollectionViewFlowLayout 做一些調(diào)整,也可以直接繼承自 UICollectionViewLayout 完全自定義布局。
自定義布局有三個必須實現(xiàn)的方法 :
class CustomLayout: UICollectionViewLayout {
override func prepare() {
// 準備布局
}
override var collectionViewContentSize: CGSize {
return CGSize(width: width, height: contentHeight)
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
return someAttributes
}
}
-
prepare: 預備階段,在這里進行一些初始化或者布局信息的計算和緩存操作 -
collectionViewContentSize:collectionView必須知道自己的內(nèi)容大小來決定滾動區(qū)域 -
layoutAttributesForElements(in:): 可見區(qū)域,當快要滾動到這個區(qū)域或者說這個區(qū)域準備渲染的時候,collectionView就會通過這個方法來獲取cell或者Supplementary View的布局信息。
UICollectionViewLayoutAttributes 中包含非常多的布局屬性。
open var frame: CGRect
open var center: CGPoint
open var size: CGSize
open var transform3D: CATransform3D
@available(iOS 7.0, *)
open var bounds: CGRect
@available(iOS 7.0, *)
open var transform: CGAffineTransform
open var alpha: CGFloat
open var zIndex: Int // default is 0
open var isHidden: Bool
open var indexPath: IndexPath
如果你覺得這個屬性不夠用,你還可以繼承他 實現(xiàn)自己的 Attributes 。
下面看下 UICollectionViewLayout 除了那三個方法,還為我們提供了哪些常用的屬性和方法(一些不常用的暫且忽略,因為我也沒用過...)。
類屬性 layoutAttributesClass , 重寫這個返回我們自定義的 Attributes 就可以實現(xiàn)我上面說的自定義 Attributes了。
layoutAttributesForItem(at: ) -> UICollectionViewLayoutAttributes? 可以重寫這個方法,返回每個indexPath對應的attribute
layoutAttributesForSupplementaryView(ofKind: at: ) -> UICollectionViewLayoutAttributes? 重寫此方法返回indexPath對應的SupplementaryView , 后面寫粘性sectionHeader ,和整個 UICollectionView 的Header 會用到此方法。
其實還有一個DecorationView ,對section的背景之類的進行裝飾。 比如對每個section設置不同的背景色什么的,這時你需要用到如下方法
layoutAttributesForDecorationView(ifKind: at:) -> UICollectionViewLayoutAttributes?
shouldInvalidateLayout(forBoundsChange: )-> Bool 此方法傳入新的bounds,可以根據(jù)次bounds決定是否需要重新計算布局。 返回true代表重新計算,比如 IndexPath(item: 0,section: 0) 我們已經(jīng)計算過了,它被滑動出了屏幕外,等再次滑動進來的時候是否還需要重新計算,如果計入視線的時候我們是根據(jù)位置實時變幻的 那就需要每次都計算,這個根據(jù)實際情況而定。
下面幾個方法是在元素被添加、刪除等的時候做一些動畫的
// 此方法用來表示 執(zhí)行的Action和操作的indexPath
open func prepare(forCollectionViewUpdates updateItems: [UICollectionViewUpdateItem])
// 一般用來做insetItem的動畫的
open func initialLayoutAttributesForAppearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes?
// 一般用來做deleteItem的動畫的
override func finalLayoutAttributesForDisappearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes?
以上這些理論看著著實有些枯燥,后面幾篇開始實戰(zhàn)。上面的大部分方法后面都會用到。