UICollectionView 03 - 自定義布局原理篇

目錄

項目下載地址: 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)。上面的大部分方法后面都會用到。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容