1. 程式人生 > >詳細分享UICollectionView的自定義布局(瀑布流, 線性, 圓形...)

詳細分享UICollectionView的自定義布局(瀑布流, 線性, 圓形...)

init hide 屬性 png 繼承 del 屏幕旋轉 結束 效果

前言:

本篇文章不是分享collectionView的詳細使用教程, 而是屬於比較高級的collectionView使用技巧, 閱讀之前, 我想你已經很熟悉collectionView的基本使用, 如果不是很熟悉, 建議在以後熟悉一下. 那麽在本篇結束後, 你也能夠很輕松的使用collectionView來實現, 當下比較流行和比較炫酷的效果以及你想要自己實現的其他的效果.這裏就實現三種比較常用的效果: 線性布局, 瀑布流布局, 圓形布局, 其他的各種自定義的布局你將是會有能力自己實現的

最終效果

技術分享圖片

技術分享圖片

技術分享圖片

一` 首先了解下UICollectionViewLayoutAttributes,

  • 當你看這些屬性的時候, 有沒有感覺到是一個view應該有的屬性, 實際上, collectionVIew裏面的所有的cell我們並沒有給它直接設置過他在collectionView上面的frame等屬性, 它的相關的設置都是由UICollectionViewLayoutAttributes來完成的.
  • 每一個cell都對應的有一個UICollectionViewLayoutAttributes來設置他的一些屬性, 當我們在修改他對應的UICollectionViewLayoutAttributes的相關的屬性的時候, 就間接的實現了對響應的cell的相關屬性的修改.
  • 所以我們對collectionViewCell的很多自定義就落在了對相應的UICollectionViewLayoutAttributes上面
  •  1 public var frame: CGRect
     2     public var center: CGPoint
     3     public var size: CGSize
     4 // 用於實現一些3D效果 
     5     public var transform3D: CATransform3D
     6     @available(iOS 7.0, *)
     7     public var bounds: CGRect
     8     @available(iOS 7.0, *)
     9 // 更改transform可以方便的實現一些縮放, 旋轉效果
    10     public var transform: CGAffineTransform
    
    11 public var alpha: CGFloat 12 public var zIndex: Int // default is 0 13 // 初始化方法, 分別對應為collectionView裏面的幾種reusebleView 14 //cell 15 public convenience init(forCellWithIndexPath indexPath: NSIndexPath) 16 //SupplementaryView 17 public convenience init(forSupplementaryViewOfKind elementKind: String, withIndexPath indexPath: NSIndexPath) 18 // DecorationView 19 public convenience init(forDecorationViewOfKind decorationViewKind: String, withIndexPath indexPath: NSIndexPath)

    二` 了解UICollectionViewFlowLayout

    • 要完成collectionView的布局是需要設置他的屬性 collectionViewLayout, 當使用storyboard的時候是默認為UICollectionViewFlowLayout
    • UICollectionViewFlowLayout是系統提供的一種網格布局, 通常情況下你只需要設置一下下面列舉的一些屬性, 就可以達到普通的collectionView的使用效果---網格效果, 同時你可以使用UICollectionViewDelegateFlowLayout 來實現一些比較簡單的動態更改cell的布局的效果
    技術分享圖片
     1 // 最小的行距
     2     public var minimumLineSpacing: CGFloat
     3 // 最小的列距
     4     public var minimumInteritemSpacing: CGFloat
     5 // cell的大小
     6     public var itemSize: CGSize
     7 // collectionView的滾動方向
     8     public var scrollDirection: UICollectionViewScrollDirection // default is UICollectionViewScrollDirectionVertical
     9 // headersize
    10     public var headerReferenceSize: CGSize
    11     public var footerReferenceSize: CGSize
    12     public var sectionInset: UIEdgeInsets
    13     ```
    14 
    15 ####三` 強大的UICollectionViewLayout
    16  * 要完成collectionView的布局是需要設置他的屬性 collectionViewLayout, 當使用storyboard的時候是默認為UICollectionViewFlowLayout, 實際上UICollectionViewFlowLayout是繼承自UICollectionViewLayout, 由系統實現的一種collectionView的布局
    17  * 所以我們可以繼承UICollectionViewLayout來自定義我們想要的布局
    18  * 實現自定義的布局並不是很復雜, 官方文檔中已經說明了相關的方法, 這裏直接分享給大家
    19 
    20 下面是自定義UICollectionViewLayout時比較常用到的一些方法
    21 
    22 1. collectionView每次需要重新布局(初始, layout 被設置為invalidated ...)的時候會首先調用這個方法prepareLayout()
    View Code

    所以Apple建議我們可以重寫這個方法來為自定義布局做一些準備的操作,
    在cell比較少的情況下, 我們一般都可以在這個方法裏面計算好所有的cell布局
    並且緩存下來, 在需要的時候直接取相應的值即可, 以提高效率
    func prepareLayout()

    2. 然後會調用layoutAttributesForElementsInRect(rect: CGRect)方法獲取到rect範圍內的cell的所有布局, 這個rect大家可以打印出來看下, 和collectionView的bounds不一樣, size可能比collectionView大一些, 這樣設計也許是為了緩沖

    Apple要求這個方法必須重寫, 並且提供相應rect範圍內的cell的所有布局的
    UICollectionViewLayoutAttributes, 如果之前我們已經計算好了,
    就可以直接返回就可以了, 當然你可以比如只返回rect範圍內的cell的布局,
    而不是所有的cell的布局, 不過這樣的話你需要設置下一個方法
    func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]?

    1 3. 當collectionView的bounds變化的時候會調用
    2 shouldInvalidateLayoutForBoundsChange(newBounds: CGRect)這個方法

    如果我們的布局是會時刻變化的, 需要在滾動的過程中重新布局 , 那麽我們需要
    設置這個方法的返回值為true, 默認為false

    • 當返回值為true的時候會將collectionView的layout設置為invalidated,
      將會使collectionView重新調用上面的prepareLayout()...方法重新獲得布局
    • 同時, 當屏幕旋轉的時候collectionView的bounds也會調用這個方法
      如果設置為false, 那麽將不會達到屏幕適配的效果,
    • 需要註意的是, 當collectionView執行一些操作(delete insert reload)等的時候,
      不會調用這個方法, 會直接重新調用上面的prepareLayout()...方法重新獲得布局
      public func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool
    4. 需要設置collectionView 的滾動範圍 collectionViewContentSize()
    

    自定義的時候, 必須重寫這個方法, 並且返回正確的滾動範圍, collectionView才能正常的滾動
    public func collectionViewContentSize() -> CGSize

    1 5. 以下方法, Apple建議我們也重寫, 返回正確的自定義對象的布局
    2 因為有時候當collectionView執行一些操作(delete insert reload)等系統會調用這些方法獲取布局, 如果沒有重寫, 可能發生意想不到的效果

    自定義cell布局的時候重寫
    public func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes?
    自定義SupplementaryView的時候重寫
    public func layoutAttributesForSupplementaryViewOfKind(elementKind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes?
    自定義DecorationView的時候重寫
    public func layoutAttributesForDecorationViewOfKind(elementKind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes?

    6. 這個方法是當collectionView將停止滾動的時候調用, 我們可以重寫它來實現, collectionView停在指定的位置(比如照片瀏覽的時候, 你可以通過這個實現居中顯示照片...)
    

    public func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint

詳細分享UICollectionView的自定義布局(瀑布流, 線性, 圓形...)