import Foundation
import UIKit
//
// UICollectionViewLayout.h
// UIKit
//
// Copyright (c) 2011-2015 Apple Inc. All rights reserved.
//
// The UICollectionViewLayout class is provided as an abstract class for subclassing to define custom collection layouts.
// 是一個(gè)抽象類味混,使用子類進(jìn)行一些自定義的 collection 視圖的布局眼姐。
// Defining a custom layout is an advanced operation intended for applications with complex needs.
// 定義一個(gè)自定義的布局是一種先進(jìn)的復(fù)雜操作的應(yīng)用程序的需求。
// 集合元素的枚舉
public enum UICollectionElementCategory : UInt {
case Cell // cell
case SupplementaryView // 補(bǔ)充視圖
case DecorationView // 裝飾視圖
}
@available(iOS 6.0, *)
// 布局屬性
public class UICollectionViewLayoutAttributes : NSObject, NSCopying, UIDynamicItem {
// 位置和尺寸
public var frame: CGRect
// 中心點(diǎn)
public var center: CGPoint
// 大小
public var size: CGSize
// 3d 變換
public var transform3D: CATransform3D
@available(iOS 7.0, *)
// 大小
public var bounds: CGRect
@available(iOS 7.0, *)
// 2d 變換
public var transform: CGAffineTransform
// 透明度
public var alpha: CGFloat
// z 軸的層疊關(guān)系
public var zIndex: Int // default is 0
// 是否隱藏
public var hidden: Bool // As an optimization, UICollectionView might not create a view for items whose hidden attribute is YES
// 索引
public var indexPath: NSIndexPath
// 顯示的是那種類型的視圖
public var representedElementCategory: UICollectionElementCategory { get }
// header 還是 footer
public var representedElementKind: String? { get } // nil when representedElementCategory is UICollectionElementCategoryCell
// 便利構(gòu)造器
public convenience init(forCellWithIndexPath indexPath: NSIndexPath)
public convenience init(forSupplementaryViewOfKind elementKind: String, withIndexPath indexPath: NSIndexPath)
public convenience init(forDecorationViewOfKind decorationViewKind: String, withIndexPath indexPath: NSIndexPath)
}
// 集合視圖的更新動(dòng)作
public enum UICollectionUpdateAction : Int {
case Insert
case Delete
case Reload
case Move
case None
}
@available(iOS 6.0, *)
// 集合視圖更新的模型
public class UICollectionViewUpdateItem : NSObject {
// 更新之前的索引
public var indexPathBeforeUpdate: NSIndexPath? { get } // nil for UICollectionUpdateActionInsert
// 更新之后的索引
public var indexPathAfterUpdate: NSIndexPath? { get } // nil for UICollectionUpdateActionDelete
// 更新操作
public var updateAction: UICollectionUpdateAction { get }
}
@available(iOS 7.0, *)
// 集合視圖布局失效的上下文
public class UICollectionViewLayoutInvalidationContext : NSObject {
// 失效任何
public var invalidateEverything: Bool { get } // set to YES when invalidation occurs because the collection view is sent -reloadData
// 無效的數(shù)據(jù)源個(gè)數(shù)
public var invalidateDataSourceCounts: Bool { get } // if YES, the layout should requery section and item counts from the collection view - set to YES when the collection view is sent -reloadData and when items are inserted or deleted
@available(iOS 8.0, *)
public func invalidateItemsAtIndexPaths(indexPaths: [NSIndexPath])
@available(iOS 8.0, *)
public func invalidateSupplementaryElementsOfKind(elementKind: String, atIndexPaths indexPaths: [NSIndexPath])
@available(iOS 8.0, *)
public func invalidateDecorationElementsOfKind(elementKind: String, atIndexPaths indexPaths: [NSIndexPath])
@available(iOS 8.0, *)
public var invalidatedItemIndexPaths: [NSIndexPath]? { get }
@available(iOS 8.0, *)
public var invalidatedSupplementaryIndexPaths: [String : [NSIndexPath]]? { get } // keys are element kind strings - values are NSArrays of NSIndexPaths
@available(iOS 8.0, *)
public var invalidatedDecorationIndexPaths: [String : [NSIndexPath]]? { get } // keys are element kind strings - values are NSArrays of NSIndexPaths
@available(iOS 8.0, *)
public var contentOffsetAdjustment: CGPoint // delta to be applied to the collection view's current contentOffset - default is CGPointZero
@available(iOS 8.0, *)
public var contentSizeAdjustment: CGSize // delta to be applied to the current content size - default is CGSizeZero
// Reordering support
@available(iOS 9.0, *)
public var previousIndexPathsForInteractivelyMovingItems: [NSIndexPath]? { get } // index paths of moving items prior to the invalidation
@available(iOS 9.0, *)
public var targetIndexPathsForInteractivelyMovingItems: [NSIndexPath]? { get } // index paths of moved items following the invalidation
@available(iOS 9.0, *)
public var interactiveMovementTarget: CGPoint { get }
}
@available(iOS 6.0, *)
// 集合視圖布局
public class UICollectionViewLayout : NSObject, NSCoding {
public init()
public init?(coder aDecoder: NSCoder)
// Methods in this class are meant to be overridden and will be called by its collection view to gather layout information.
// To get the truth on the current state of the collection view, call methods on UICollectionView rather than these.
// 正在使用這個(gè)布局的集合視圖
public var collectionView: UICollectionView? { get }
// MARK: - iOS 10
// 返回集合視圖 內(nèi)容的 寬度和高度
/*
collectionViewContentSize() -> CGSize 方法的替代品窃祝。
子類必須重寫這個(gè)屬性的 get 方法掐松,返回 集合視圖內(nèi)容的寬高踱侣。
這個(gè)值代表的是左右內(nèi)容的寬和高,不僅僅是當(dāng)前顯示的內(nèi)容的寬高大磺。
集合視圖使用這個(gè)信息去配置自己的 contentSize 從而導(dǎo)致可以滾動(dòng)抡句。
*/
public var collectionViewContentSize: CGSize { get }
// Call -invalidateLayout to indicate that the collection view needs to requery the layout information.
// Subclasses must always call super if they override.
// 調(diào)用 -invalidateLayout 表明, 集合視圖需要重新查詢布局信息
// 子類必須總是調(diào)用父類
public func invalidateLayout()
@available(iOS 7.0, *)
// 布局失效的上下文
public func invalidateLayoutWithContext(context: UICollectionViewLayoutInvalidationContext)
// 注冊裝飾視圖
public func registerClass(viewClass: AnyClass?, forDecorationViewOfKind elementKind: String)
public func registerNib(nib: UINib?, forDecorationViewOfKind elementKind: String)
}
extension UICollectionViewLayout {
// 布局屬性類杠愧,
// 重載這個(gè)類待榔,是為了提供一個(gè)自定義的 UICollectionViewLayoutAttributes 來使用
public class func layoutAttributesClass() -> AnyClass // override this method to provide a custom class to be used when instantiating instances of UICollectionViewLayoutAttributes
@available(iOS 7.0, *)
// 失效的上下文類
// 重載這個(gè)類,主要是提供一個(gè)自定義的失效上下文
public class func invalidationContextClass() -> AnyClass
// override this method to provide a custom class to be used for invalidation contexts
// MARK: - 準(zhǔn)備布局
/*
The collection view calls -prepareLayout once at its first layout as the first message to the layout instance.
布局對象進(jìn)行第一次布局的時(shí)候 collection view 會(huì)調(diào)用這個(gè)方法
The collection view calls -prepareLayout again after layout is invalidated and before requerying the layout information.
collection view 會(huì)在布局失效后流济,和查詢新的布局信息之前調(diào)用這個(gè)方法锐锣。
Subclasses should always call super if they override.
子類必須總是調(diào)用父類
注意: 這個(gè)方法主要是告訴布局對象更新當(dāng)前的布局信息
布局更新發(fā)生:
* 在 collection view 第一次呈現(xiàn)內(nèi)容的時(shí)候。
* 無論在什么時(shí)候由于視圖的改變導(dǎo)致的 布局明確的失效和隱含的失效都會(huì)導(dǎo)致布局更新
在每個(gè)布局更新期間绳瘟, collection view 調(diào)用這個(gè)方法的第一次的時(shí)候會(huì)給你的布局對象一次準(zhǔn)備即將到來的布局操作的機(jī)會(huì)雕憔。
這個(gè)方法默認(rèn)實(shí)現(xiàn)沒有做任何事情。子類能夠重載這個(gè)方法糖声,使用這個(gè)方法設(shè)置一些數(shù)據(jù)結(jié)構(gòu)和完成一些完成布局需要的初始化計(jì)算斤彼。
*/
public func prepareLayout()
// MARK: - 布局信息的確認(rèn)
// UICollectionView calls these four methods to determine the layout information.
// UICollectionView 調(diào)用下面 4 個(gè)方法來群的個(gè)布局信息。
// Implement -layoutAttributesForElementsInRect: to return layout attributes for for supplementary or decoration views, or to perform layout in an as-needed-on-screen fashion.
// 實(shí)現(xiàn) -layoutAttributesForElementsInRect: 去給 supplementary 或 decoration 返回一個(gè)布局屬性蘸泻,或者需要在屏幕上完成一個(gè)需要的布局
// Additionally, all layout subclasses should implement -layoutAttributesForItemAtIndexPath: to return layout attributes instances on demand for specific index paths.
// 此外琉苇,所有的布局子類,將實(shí)現(xiàn) -layoutAttributesForItemAtIndexPath: 方法去返回一個(gè)布局屬性悦施,需要指定索引并扇。
// If the layout supports any supplementary or decoration view types, it should also implement the respective atIndexPath: methods for those types.
// 如果布局對象支持任何的 補(bǔ)充視圖和 裝飾視圖類型, 還應(yīng)該實(shí)現(xiàn)各自的 atIndexPath: 方法歼争。
// return an array layout attributes instances for all the views in the given rect
// 返回一個(gè) 布局屬性數(shù)組拜马,在給定 rect 里面的所有視圖。
/**
方法默認(rèn)返回時(shí) nil 沐绒,返回值是代表所有 cel 和 view 的布局信息的 布局屬性對象數(shù)組俩莽。
創(chuàng)建布局屬性的時(shí)候,總是創(chuàng)建代表正確元素類型的布局屬性乔遮。集合視圖會(huì)根據(jù)屬性的類型來區(qū)分不同的屬性扮超。使用這些信息來決怎么創(chuàng)建哪些視圖和如何管理視圖。
*/
public func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]?
// 獲取指定 indexPath 的 cell 的布局屬性
// 布局屬性包含提供給 item 的所有信息蹋肮, 使用這個(gè)方法得到的布局信息只對某個(gè) item 有效
public func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes?
// 獲取 指定index 和 kind 的補(bǔ)充視圖布局屬性
// 如果有補(bǔ)充視圖出刷,就必須重載這個(gè)方法,并使用這個(gè)方法獲取布局屬性坯辩。
public func layoutAttributesForSupplementaryViewOfKind(elementKind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes?
// 獲取裝飾視圖的布局屬性
public func layoutAttributesForDecorationViewOfKind(elementKind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes?
// return YES to cause the collection view to requery the layout for geometry information
// 返回 yes 去引起 集合視圖詢問布局的幾何信息
// 是否由于 bounds 的改變來觸發(fā)布局失效
public func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool
@available(iOS 7.0, *)
// 由于 bounds 改變而導(dǎo)致的布局失效上下文
public func invalidationContextForBoundsChange(newBounds: CGRect) -> UICollectionViewLayoutInvalidationContext
@available(iOS 8.0, *)
// 布局失效 偏好布局屬性
public func shouldInvalidateLayoutForPreferredLayoutAttributes(preferredAttributes: UICollectionViewLayoutAttributes, withOriginalAttributes originalAttributes: UICollectionViewLayoutAttributes) -> Bool
@available(iOS 8.0, *)
public func invalidationContextForPreferredLayoutAttributes(preferredAttributes: UICollectionViewLayoutAttributes, withOriginalAttributes originalAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutInvalidationContext
// 目標(biāo)內(nèi)容的偏移量
// return a point at which to rest after scrolling - for layouts that want snap-to-point scrolling behavior
// 返回一個(gè)停止?jié)L動(dòng)的點(diǎn)馁龟。
// collection view 停止?jié)L動(dòng)會(huì)調(diào)用這個(gè)方法。
/*
proposedContentOffset : 滾動(dòng)停止后漆魔,左上角可見視圖的偏移量
velocity: x 軸和 y 軸的滾動(dòng)速度
你可以使用一個(gè)你想要的值進(jìn)行替換坷檩。 默認(rèn)實(shí)現(xiàn)就是 proposedContentOffset 參數(shù)
方法重載:
如果你想要快速滾動(dòng)到一個(gè)指定的邊界却音, 你可以重載這個(gè)方法,更改這個(gè)停止的點(diǎn)矢炼。 例如系瓢,你可以使用這個(gè)方法總是停止在邊界內(nèi)某個(gè)items 之間,或者是 item 的中間句灌。
*/
public func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint
@available(iOS 7.0, *)
// a layout can return the content offset to be applied during transition or update animations
/*
在使用一個(gè)動(dòng)畫布局進(jìn)行更新或改變后夷陋,返回一個(gè) 內(nèi)容的偏移量。
proposedContentOffset: 推薦的一個(gè)偏移點(diǎn)胰锌。是可視內(nèi)容左上角的一個(gè)點(diǎn)骗绕。
這代表點(diǎn),集合視圖計(jì)算動(dòng)畫結(jié)束,最可能使用的值资昧。 這個(gè)方法的默認(rèn)實(shí)現(xiàn)值直接返回 proposedContentOffset 的值爹谭。
你可以使用一個(gè)你想要替代的 偏移量返回。
在布局更新期間榛搔,或者布局過度期間。這個(gè) collection view 會(huì)調(diào)用這個(gè)方法东揣,去給你一個(gè)機(jī)會(huì)去改變 推薦的偏移量践惑,使用在結(jié)束動(dòng)畫上。
方法的重載:
如果動(dòng)畫或者 過度效果 可能引起 items 的 positioned 和你的設(shè)計(jì)不吻合的時(shí)候嘶卧,可以重載這個(gè)方法尔觉。
collection view 回調(diào)用 這個(gè)方法之后,調(diào)用 prepare() 和 collectionViewContentSize 方法芥吟。
*/
public func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint) -> CGPoint
/*
Subclasses must override this method and use it to return the width and height of the collection view’s content.
子類必須重載這個(gè)方法侦铜,去返回 collection view’s content 的寬度和高度。
These values represent the width and height of all the content, not just the content that is currently visible.
這個(gè)值代表著所有內(nèi)容的寬度和高度钟鸵,不單單是可見內(nèi)容的寬度和高度钉稍。
The collection view uses this information to configure its own content size to facilitate scrolling.
集合視圖會(huì)使用這個(gè)信息配置自己內(nèi)容的尺寸來促使可以滾動(dòng)
*/
public func collectionViewContentSize() -> CGSize
}
extension UICollectionViewLayout {
// It will be called prior to calling the initial/final layout attribute methods below to give the layout an opportunity to do batch computations for the insertion and deletion layout attributes.
// The updateItems parameter is an array of UICollectionViewUpdateItem instances for each element that is moving to a new index path.
// 通知布局對象, collection view 的 content 發(fā)生了改變
/*
通知布局對象棺耍,collection view 的 content 即將改變贡未。
This method is called when there is an update with deletes/inserts to the collection view.
當(dāng) collection view 的 items 進(jìn)行 deletes 和 inserts 會(huì)通知布局對象調(diào)用這個(gè)方法。以至于 布局對象可以根據(jù)需求對布局進(jìn)行調(diào)整蒙袍。
第一個(gè)過程是俊卤,調(diào)用這個(gè)方法讓布局對象知道預(yù)期的變化,之后再收集布局的 插入害幅,刪除消恍,移動(dòng) 信息在 collection view 進(jìn)行動(dòng)畫。
*/
public func prepareForCollectionViewUpdates(updateItems: [UICollectionViewUpdateItem])
/*
執(zhí)行所需的任何額外的動(dòng)畫或清理集合視圖中更新以现。
集合視圖調(diào)用這個(gè)方法作為動(dòng)畫的任何改變之前最后一步狠怨。這個(gè)方法會(huì)在 插入约啊,添加,刪除的 block 動(dòng)畫執(zhí)行完畢后調(diào)用取董,以至于你可以添加一些附加的動(dòng)畫棍苹。
因此,您可以使用它來執(zhí)行任何最后一分鐘的任務(wù)與管理你的布局對象的狀態(tài)信息。
*/
public func finalizeCollectionViewUpdates() // called inside an animation block after the update
// MARK: 協(xié)調(diào)動(dòng)畫變化
public func prepareForAnimatedBoundsChange(oldBounds: CGRect) // UICollectionView calls this when its bounds have changed inside an animation block before displaying cells in its new bounds
public func finalizeAnimatedBoundsChange() // also called inside the animation block
// MARK: layout 之間的過度
// UICollectionView calls this when prior the layout transition animation on the incoming and outgoing layout
@available(iOS 7.0, *)
public func prepareForTransitionToLayout(newLayout: UICollectionViewLayout)
@available(iOS 7.0, *)
public func prepareForTransitionFromLayout(oldLayout: UICollectionViewLayout)
@available(iOS 7.0, *)
public func finalizeLayoutTransition() // called inside an animation block after the transition
// This set of methods is called when the collection view undergoes an animated transition such as a batch update block or an animated bounds change.
// For each element on screen before the invalidation, finalLayoutAttributesForDisappearingXXX will be called and an animation setup from what is on screen to those final attributes.
// For each element on screen after the invalidation, initialLayoutAttributesForAppearingXXX will be called and an animation setup from those initial attributes to what ends up on screen.
public func initialLayoutAttributesForAppearingItemAtIndexPath(itemIndexPath: NSIndexPath) -> UICollectionViewLayoutAttributes?
public func finalLayoutAttributesForDisappearingItemAtIndexPath(itemIndexPath: NSIndexPath) -> UICollectionViewLayoutAttributes?
public func initialLayoutAttributesForAppearingSupplementaryElementOfKind(elementKind: String, atIndexPath elementIndexPath: NSIndexPath) -> UICollectionViewLayoutAttributes?
public func finalLayoutAttributesForDisappearingSupplementaryElementOfKind(elementKind: String, atIndexPath elementIndexPath: NSIndexPath) -> UICollectionViewLayoutAttributes?
public func initialLayoutAttributesForAppearingDecorationElementOfKind(elementKind: String, atIndexPath decorationIndexPath: NSIndexPath) -> UICollectionViewLayoutAttributes?
public func finalLayoutAttributesForDisappearingDecorationElementOfKind(elementKind: String, atIndexPath decorationIndexPath: NSIndexPath) -> UICollectionViewLayoutAttributes?
// These methods are called by collection view during an update block.
// Return an array of index paths to indicate views that the layout is deleting or inserting in response to the update.
@available(iOS 7.0, *)
public func indexPathsToDeleteForSupplementaryViewOfKind(elementKind: String) -> [NSIndexPath]
@available(iOS 7.0, *)
public func indexPathsToDeleteForDecorationViewOfKind(elementKind: String) -> [NSIndexPath]
@available(iOS 7.0, *)
public func indexPathsToInsertForSupplementaryViewOfKind(elementKind: String) -> [NSIndexPath]
@available(iOS 7.0, *)
public func indexPathsToInsertForDecorationViewOfKind(elementKind: String) -> [NSIndexPath]
}
// MARK: - 9.0 新加的
extension UICollectionViewLayout {
@available(iOS 9.0, *)
public func targetIndexPathForInteractivelyMovingItem(previousIndexPath: NSIndexPath, withPosition position: CGPoint) -> NSIndexPath
@available(iOS 9.0, *)
// 當(dāng)用戶交互式的移動(dòng) item 的時(shí)候 返回 item 的布局屬性
/*
indexPath: item item的目標(biāo)索引, 這個(gè) indexPath 是 targetIndexPathForInteractivelyMovingItem 方法返回值
position: item 在 collection view 坐標(biāo)系中當(dāng)前的位置
返回值是在指定位置的 item 的布局屬性茵汰。
當(dāng) item 由于用戶交互的原因進(jìn)行了移動(dòng)枢里,布局對象會(huì)調(diào)用這個(gè)方法去接收一個(gè)布局屬性,并將這個(gè) 布局屬性用在指定位置的 item 上蹂午。
這個(gè)方法的默認(rèn)實(shí)現(xiàn)是返回 item 已經(jīng)存在的布局屬性的拷貝, 并對拷貝的 center 進(jìn)行修改栏豺,center = position , zIndex 也進(jìn)行了修改豆胸,zIndex = NSIntegerMax奥洼。 以至于 item 可以浮動(dòng)在 collection view items 的上面。
方法的重載:
子類可以重載這個(gè)方法晚胡,去修改一些需要的附加布局屬性灵奖。
如果重載這個(gè)方法,調(diào)用父類方法去接收一個(gè) item 已經(jīng)存在的屬性估盘。做一些你自己的改變瓷患,讓后返回這個(gè)數(shù)據(jù)結(jié)構(gòu)。
*/
public func layoutAttributesForInteractivelyMovingItemAtIndexPath(indexPath: NSIndexPath, withTargetPosition position: CGPoint) -> UICollectionViewLayoutAttributes
@available(iOS 9.0, *)
public func invalidationContextForInteractivelyMovingItems(targetIndexPaths: [NSIndexPath], withTargetPosition targetPosition: CGPoint, previousIndexPaths: [NSIndexPath], previousPosition: CGPoint) -> UICollectionViewLayoutInvalidationContext
@available(iOS 9.0, *)
public func invalidationContextForEndingInteractiveMovementOfItemsToFinalIndexPaths(indexPaths: [NSIndexPath], previousIndexPaths: [NSIndexPath], movementCancelled: Bool) -> UICollectionViewLayoutInvalidationContext
}
UICollectionViewLayout 對象的使用
UICollectionViewLayout 是一個(gè)基礎(chǔ)的抽象類遣妥,必須使用子類化擅编,使用子類來產(chǎn)生 collection view 需要的布局信息。布局對象的工作是去決定在 collection view 范圍內(nèi)部 cell, supplementary, decoration 視圖的位置箫踩,在需要的時(shí)候向 collection view 報(bào)告這些信息爱态。collection view 根據(jù)響應(yīng)的布局相應(yīng)的視圖以至于視圖能夠在屏幕上顯示。
你必須子類化 UICollectionViewLayout 去使用境钟。在你考慮子類化之前锦担, 查看 UICollectionViewFlowLayout 類是否能夠滿足你的布局需求。
子類化注意事項(xiàng)
布局對象的主要工作是提供在 collection view 內(nèi)的 item 的 位置和 視覺狀態(tài)信息吱韭。布局對象不會(huì)根據(jù)提供的布局來創(chuàng)建視圖吆豹。視圖是被 collection view 的數(shù)據(jù)源創(chuàng)建的。相反理盆,布局對象定義了根據(jù)布局設(shè)計(jì)的視覺元素的位置和尺寸痘煤。
Collection view 有三個(gè)類型的視覺元素需要去布局:
- cell:
- Supplementary views
- Decoration Views
方法重載
每一個(gè)布局對象將要實(shí)現(xiàn)下面這些方法:
collectionViewContentSize
// 確定集合視圖內(nèi)容的尺寸(這個(gè) contentSize 決定了 collection view 的滾動(dòng)范圍)
layoutAttributesForElements(in:)
// 返回素有元素(cell, Supplementary views, Decoration Views) 的布局屬性
layoutAttributesForItem(at:)
// 返回 item 的布局屬性
*下面兩個(gè)方法只在需要的時(shí)候重載
layoutAttributesForSupplementaryView(ofKind:at:) (if your layout supports supplementary views)
// 返回 Supplementary views 的布局屬性
layoutAttributesForDecorationView(ofKind:at:) (if your layout supports decoration views)
// 返回 Decoration Views 的布局屬性
shouldInvalidateLayout(forBoundsChange:)
// 是否由于 collection view bounds 的改變而實(shí)現(xiàn)布局(進(jìn)行重新布局)
這些方法提供了 collection view 需要去設(shè)置屏幕上內(nèi)容位置的基本的布局信息。當(dāng)然猿规,如果你的布局不需要支持 supplementary 或 decoration views 衷快,你就不需要實(shí)現(xiàn)相應(yīng)的方法。
當(dāng) collection view 的 data 發(fā)生改變(item 進(jìn)行了 刪除姨俩,插入)的時(shí)候蘸拔, collection view 要求布局對象去更新布局信息师郑。
尤其是,任何 item 被 moved调窍, added 宝冕,deleted 必須對 item 的布局信息進(jìn)行更新,去映射到新的位置邓萨。
- 對于 item 的移動(dòng)地梨, collection view 使用標(biāo)準(zhǔn)的方法去獲取 item 更新的布局屬性。
- 對于 item 的插入和刪除缔恳, collection view 會(huì)調(diào)用一些不同的方法宝剖,你需要重載這些方法,提供恰當(dāng)?shù)牟季中畔?/li>
插入和刪除需要重載的方法
initialLayoutAttributesForAppearingItem(at:)
initialLayoutAttributesForAppearingSupplementaryElement(ofKind:at:)
initialLayoutAttributesForAppearingDecorationElement(ofKind:at:)
finalLayoutAttributesForDisappearingItem(at:)
finalLayoutAttributesForDisappearingSupplementaryElement(ofKind:at:)
finalLayoutAttributesForDisappearingDecorationElement(ofKind:at:)
除了上面的這些方法歉甚,你還可以重載
// 處理任何布局相關(guān)的操作
prepare(forCollectionViewUpdates:)
// 使用這個(gè)方法万细,添加動(dòng)畫到整體的動(dòng)畫塊中
// 或者實(shí)現(xiàn)一些最終的布局相關(guān)的任務(wù)。
finalizeCollectionViewUpdates()
使用失效上下文來優(yōu)化布局性能
當(dāng)設(shè)計(jì)你的自定義布局的時(shí)候纸泄, 只有你布局的那一部分真實(shí)的發(fā)生改變的時(shí)候使用 invalidating 可以提高性能赖钞。 當(dāng)你改變 items 的時(shí)候 , 調(diào)用 invalidateLayout()
方法聘裁,觸發(fā) collection view 重新計(jì)算 collection view 申請的所有的布局信息仁烹。更好的解決方案是只去重新計(jì)算發(fā)生改變的布局信息,這恰好是 invalidation contexts 允許你這么去做的咧虎。 一個(gè) invalidation context 告訴你 那一部分的布局發(fā)生了改變。布局對象能夠使用這些信息去減少大量的重復(fù)計(jì)算计呈。
子類化 UICollectionViewLayoutInvalidationContext 類砰诵, 給你的布局對象自定義一個(gè)失效上下文。在你的子類里面捌显,定義自定義的屬性茁彭,來代表你布局的那一部分?jǐn)?shù)據(jù),致使這一部分?jǐn)?shù)據(jù)可以被獨(dú)立重新計(jì)算扶歪。當(dāng)你需要在運(yùn)行時(shí)失效你的布局理肺,創(chuàng)建一個(gè)你的失效上下文實(shí)例對象的子類,配置一些基于布局信息改變的自定義屬性善镰, 并將該對象傳遞給你的布局invalidateLayout(:)方法妹萨。在這些方法的自定義實(shí)現(xiàn)里面你可以使用 invalidation context 里面的信息去重新計(jì)算你布局發(fā)生改變的那一部分。
如果你給你的布局對象自定義了 invalidation context 上下文類炫欺,你將要重載 布局對象的 invalidationContextClass()
方法乎完,去返回你自定義的類。 collection view 當(dāng)需要一個(gè)失效上下文的時(shí)候總是創(chuàng)建一個(gè)你指定類的實(shí)例對象品洛。 從這個(gè)方法返回您的自定義子類可以確保您的布局對象總是預(yù)計(jì)的失效上下文树姨。