UICollectionView包含三種類型的視覺元素:
- 單元格
Cells:用于展示內(nèi)容的主要元素,每個單元格表示集合中的單個數(shù)據(jù)項;
具有交互性,以便用戶可以執(zhí)行選擇、拖動和重新排序單元格等操作; - 補充視圖
Supplementary views:可以理解為每個Section的Header或者Footer;用來實現(xiàn)指定部分或整個集合視圖的頁眉和頁腳視圖;
補充視圖是可選的,它們的使用和位置由布局對象定義; - 裝飾視圖
DecorationViews:視覺裝飾,每個Section的背景,不被 DataSounce 控制;
是可選的,它們的使用和位置由布局對象定義。
UICollectionView 根據(jù)布局信息,將這些視圖顯示在屏幕上, 每次將項插入到UICollectionView或刪除項時,都會對添加或刪除的項進行額外的布局傳遞。
1、視圖中每個項的布局屬性
UICollectionViewLayoutAttributes 是封裝的一個布局對象,用于管理 UICollectionView 中每個項的布局屬性!
@interface UICollectionViewLayoutAttributes : NSObject <NSCopying, UIDynamicItem>
/** 指定項的坐標(biāo)
* 該值的設(shè)定,將影響到屬性 center 與 size
*/
@property (nonatomic) CGRect frame;
/** 指定項的中點坐標(biāo)
* 該值的設(shè)定,將更新屬性 frame.origin
*/
@property (nonatomic) CGPoint center;
/** 指定項的 size
* 該值的設(shè)定,將更新屬性 frame.size 和 bounds.size
*/
@property (nonatomic) CGSize size;
/** 指定項的三維變換
*/
@property (nonatomic) CATransform3D transform3D;
/** 指定項的邊界
* 設(shè)置 bounds.size 也將更新屬性 size
*/
@property (nonatomic) CGRect bounds API_AVAILABLE(ios(7.0));
/** 指定項的仿射變換
* @discussion CGAffineTransform 是一個用于繪制2D圖形的仿射變換矩陣,用于做旋轉(zhuǎn)、縮放、平移等
*/
@property (nonatomic) CGAffineTransform transform API_AVAILABLE(ios(7.0));
/** 指定項的透明度,默認(rèn)值是 1.0
* 取值范圍:[0.0,1.0] ,0.0 表示完全透明,1.0 表示不透明
*/
@property (nonatomic) CGFloat alpha;
/** 指定項在 z 坐標(biāo)軸的坐標(biāo),默認(rèn)值為 0
* 該值用于確定布局期間項目的 front-to-back 層級。索引值較高的項出現(xiàn)在值較低的項之上。
* 具有相同值的項具有未確定的順序
*/
@property (nonatomic) NSInteger zIndex; // default is 0
/** 指定的項是否顯示,默認(rèn)顯示值為 NO
* 作為一種優(yōu)化,如果將此屬性設(shè)置為YES,則 UICollectionView 可能不會創(chuàng)建相應(yīng)的視圖
*/
@property (nonatomic, getter=isHidden) BOOL hidden;
/** 指定項在 UICollectionView 上的索引路徑
* indexPath.section 與 indexPath.item 兩個值唯一確定指定項的位置
*/
@property (nonatomic, strong) NSIndexPath *indexPath;
/** 指定項的類型
* 可以使用此屬性中的值來區(qū)分布局屬性是用于單元格、補充視圖還是裝飾視圖。
* <ul> UICollectionElementCategory 的枚舉值:
* <li> UICollectionElementCategoryCell 指定項是一個 cell
* <li> UICollectionElementCategorySupplementaryView 指定項是一個 supplementary view
* <li> UICollectionElementCategoryDecorationView 指定項是一個 DecorationView
* </ul>
*/
@property (nonatomic, readonly) UICollectionElementCategory representedElementCategory;
/** targetView 特定于布局的標(biāo)識符
* 使用該值來標(biāo)識被關(guān)聯(lián)的補充視圖或裝飾視圖的特定用途。
* @note 如果屬性 representedElementCategory = UICollectionElementCategoryCell值,則該值為 nil
*/
@property (nonatomic, readonly, nullable) NSString *representedElementKind;
/** 創(chuàng)建一個指定路徑的 cell 的布局屬性
* @parma indexPath 單元格 cell 的索引路徑
*/
+ (instancetype)layoutAttributesForCellWithIndexPath:(NSIndexPath *)indexPath;
/** 創(chuàng)建一個指定路徑的 SupplementaryView 的布局屬性
* @parma elementKind 標(biāo)識補充視圖類型的字符串
* <li> UICollectionElementKindSectionHeader 頭部
* <li> UICollectionElementKindSectionFooter 尾部
* @parma indexPath 補充視圖 SupplementaryView 的索引路徑
* @discussion 補充視圖通常是為特殊目的而設(shè)計的,例如,頁眉和頁腳視圖的布局與單元格不同,可以為單個部分或作為一個整體提供給 CollectionView
*/
+ (instancetype)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind withIndexPath:(NSIndexPath *)indexPath;
/** 創(chuàng)建一個指定路徑的 DecorationView 的布局屬性
* @parma decorationViewKind 標(biāo)識裝飾視圖類型的標(biāo)識符
* @parma indexPath 裝飾視圖 DecorationView 的索引路徑
* @discussion 裝飾視圖不被 CollectionView 的 dataSource 管理,它們主要為一個部分或整個集合視圖提供視覺裝飾。
* 使用參數(shù) indexPath 來標(biāo)識給定的裝飾視圖
*/
+ (instancetype)layoutAttributesForDecorationViewOfKind:(NSString *)decorationViewKind withIndexPath:(NSIndexPath *)indexPath;
@end
2、UICollectionView 的布局管理
UICollectionViewLayout 是為 UICollectionView 生成布局信息的抽象基類:該對象確定單元格、補充視圖和裝飾視圖在 UICollectionView 內(nèi)的位置;UICollectionView 將提供的布局信息應(yīng)用于相應(yīng)的視圖,以便它們可以顯示在屏幕上。
在子類化之前,考慮是否可以調(diào)整 UICollectionViewCompositionalLayout 來滿足布局需求。
2.1、 預(yù)處理:提供布局屬性
下述方法提供了 UICollectionView 在屏幕上展示視圖所需的基本布局信息。每個布局對象應(yīng)該實現(xiàn)以下方法的幾種:
@interface UICollectionViewLayout : NSObject <NSCoding>
/** 創(chuàng)建布局屬性對象時要使用的類
* 如果自定義 UICollectionViewLayoutAttributes 的子類 來管理額外的布局屬性,必須重寫該方法并返回自定義子類。
* 創(chuàng)建布局屬性的方法在創(chuàng)建新的布局屬性對象時使用這個類。
*/
@property(class, nonatomic, readonly) Class layoutAttributesClass;
/** 返回collectionView內(nèi)容的寬度和高度
* @discussion 必須重寫該方法;該值表示所有內(nèi)容的寬度和高度,而不僅僅是當(dāng)前可見的內(nèi)容,collectionView 使用該值配置自己的內(nèi)容大小,以便滾動。
* @return 默認(rèn)返回CGSizeZero
*/
@property(nonatomic, readonly) CGSize collectionViewContentSize;
/** 準(zhǔn)備更新當(dāng)前布局 :在布局更新期間,首先調(diào)用該方法,預(yù)處理布局操作;
* @discussion 當(dāng) CollectionView 第一次顯示其內(nèi)容時,需要調(diào)用 -prepareLayout 一次;
* 當(dāng)布局因視圖的更改而顯式或隱式無效時,需要再次調(diào)用 -prepareLayout ;
* @note 該方法的默認(rèn)實現(xiàn)不執(zhí)行任何操作;重寫該方法,預(yù)處理稍后布局所需的任何計算!
*/
- (void)prepareLayout;
/// UICollectionView 調(diào)用這四個方法來確定布局信息
/** 獲取指定區(qū)域中所有視圖(cell,supplementaryView,decorationViews)的布局屬性
* @param rect 指定區(qū)域
* @discussion 重寫該方法,返回所有視圖的布局屬性;不同類型的視圖,使用不同的方法創(chuàng)建、管理;
* @return 默認(rèn)返回 nil
* @note 針對固定布局,如瀑布流等可以使用數(shù)組緩存 LayoutAttributes ,不需要再次加載創(chuàng)建
* 但是對于 cell 做的特效等場景,如卡片動畫,需要實時的 LayoutAttributes,因此不能緩存,只能需要時創(chuàng)建!
*/
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect;
/** 根據(jù) indexPath 獲取 cell 對應(yīng)的布局屬性
* @param indexPath cell 的索引
* @discussion 必須重寫該方法返回 cell 的布局信息。
* @note 該方法僅為 cell 提供布局信息
*/
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;
/** 返回 SupplementaryView 的布局屬性
* @discussion 如果 CollectionView 使用了SupplementaryView,則必須重寫此方法并返回這些視圖的布局信息;
* @param elementKind 視圖 SupplementaryView 類型
* UICollectionElementKindSectionFooter
* UICollectionElementKindSectionHeader
* @param indexPath 索引
* @note 如果布局不支持補充視圖,則不必調(diào)用該方法;
*/
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath;
/** 返回裝飾視圖 DecorationView 的布局屬性
* @discussion 如果 CollectionView 使用了DecorationView,則必須重寫此方法并返回這些視圖的布局信息;
* @param elementKind 標(biāo)識裝飾視圖 DecorationView 類型
* @param indexPath 索引
* @note 如果布局不支持裝飾視圖,則不必調(diào)用該方法;
*/
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString*)elementKind atIndexPath:(NSIndexPath *)indexPath;
/** 當(dāng)用戶拖動項時,檢索項的布局屬性。
* @param indexPath 被拖動之前,項的索引路徑
* @param position 被拖動項在 UICollectionView 坐標(biāo)系中的當(dāng)前位置
* @note 如果重寫此方法,先調(diào)用super以檢索項的現(xiàn)有屬性,然后對返回的結(jié)構(gòu)進行更改
* @return 返回一個項目現(xiàn)有屬性的副本,有兩個變化:
* 中心點 center 被設(shè)置為 position,
* zIndex值被設(shè)置為NSIntegerMax,項目浮動在UICollectionView的其他項目之上
*/
- (UICollectionViewLayoutAttributes *)layoutAttributesForInteractivelyMovingItemAtIndexPath:(NSIndexPath *)indexPath withTargetPosition:(CGPoint)position API_AVAILABLE(ios(9.0));
/** 檢索在動畫布局更新或更改后使用的內(nèi)容偏移量
* @param proposedContentOffset 在 UICollectionView 的內(nèi)容視圖的坐標(biāo)空間中:可見內(nèi)容左上角的建議點;
* 表示 UICollectionView 計算出的在動畫結(jié)束時最有可能使用的值
* @return 要使用的內(nèi)容偏移量。該方法的默認(rèn)實現(xiàn)返回proposedContentOffset參數(shù)中的值。
* @discussion UICollectionView 在調(diào)用 -prepareLayout 和 -collectionViewContentSize 方法之后調(diào)用這個方法;
* 有機會更改在動畫結(jié)束時使用的proposedContentOffset; 如果動畫或轉(zhuǎn)換可能導(dǎo)致項目的定位方式不是最佳的,可以重寫此方法;
*/
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset API_AVAILABLE(ios(7.0));
/** 檢索停止?jié)L動的點
* @param proposedContentOffset 在 UICollectionView 的內(nèi)容視圖中建議停止?jié)L動的點;
* 在該值下,如果不進行任何調(diào)整,滾動將自然停止;
* @param velocity 沿水平軸和垂直軸的當(dāng)前滾動速度。該值以 每秒/點 為單位進行測量
* @return 要使用的內(nèi)容偏移量。這個值反映了調(diào)整后的可見區(qū)域的左上角。該方法的默認(rèn)實現(xiàn)返回proposedContentOffset參數(shù)中的值。
*
* 如果您希望滾動行為抓取到特定的邊界,您可以覆蓋此方法并使用它來更改停止點。
* 例如,您可以使用此方法始終在項目之間的邊界上停止?jié)L動,而不是在項目中間停止?jié)L動。
*/
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity;//return a point at which to rest after scrolling - for layouts that want snap-to-point scrolling behavior
@end
2.2、 響應(yīng) UICollectionView 更新
當(dāng) UICollectionView 中的數(shù)據(jù)發(fā)生更改并且要插入或刪除項時,布局對象需要更新布局信息; 特別地,任何被拖動、添加或刪除的項必須更新其布局信息以反映其新位置;
- 對于已拖動的項,
UICollectionView使用標(biāo)準(zhǔn)方法檢索項的更新布局屬性; - 對于被插入或刪除的項,
UICollectionView調(diào)用一些不同的方法,開發(fā)者應(yīng)該覆蓋這些方法來提供適當(dāng)?shù)牟季中畔?
/** 當(dāng)UICollectionView經(jīng)歷動畫轉(zhuǎn)換時(如批更新塊或動畫邊界更改),將調(diào)用此方法集。
* 對于屏幕上的每個元素在失效之前,finallayoutattributesfordisoriing 系列方法將被調(diào)用,并從屏幕上的內(nèi)容到這些最終屬性進行動畫設(shè)置。
* 對于失效后屏幕上的每個元素,initiallayoutattributesforappearance 系列方法將被調(diào)用,并設(shè)置從這些初始屬性到最終屏幕上的內(nèi)容的動畫。
*/
/** 檢索插入到 UICollectionView 中的項(Cell / SupplementaryView / DecorationView)的開始布局信息
* @param indexPath 要插入的項的索引路徑。
* @return 布局屬性對象,用于描述放置相應(yīng)項的位置,默認(rèn)返回nil ;
* @discussion 在調(diào)用 -prepareForCollectionViewUpdates: 和 -finalizeCollectionViewUpdates 之間調(diào)用這個方法 , 返回描述項的初始位置和狀態(tài)的布局信息;
* UICollectionView 使用這些信息作為任何動畫的起點。(動畫的終點是項目在集合視圖中的新位置。)
* 如果返回nil,布局對象使用項目的最終屬性作為動畫的開始點和結(jié)束點。
*/
- (nullable UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath;
- (nullable UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingSupplementaryElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)elementIndexPath;
- (nullable UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingDecorationElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)decorationIndexPath;
/** 檢索即將從 UICollectionView 中移除的項的最終布局信息
* @param indexPath 被刪除項的索引路徑
* @return 布局屬性對象,描述要用作移除動畫的結(jié)束點的項的位置,默認(rèn)返回nil ;
* @discussion 在調(diào)用 -prepareForCollectionViewUpdates: 和 -finalizeCollectionViewUpdates 之間調(diào)用這個方法 , 返回描述項目的最終位置和狀態(tài)的布局信息;
* UICollectionView 使用此信息作為任何動畫的終點。(動畫的起始點是項目的當(dāng)前位置。)
* 如果返回nil,布局對象對動畫的開始點和結(jié)束點使用相同的屬性。
*/
- (nullable UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath;
- (nullable UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingSupplementaryElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)elementIndexPath;
- (nullable UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingDecorationElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)decorationIndexPath;
除了上述方法之外,還可以重寫以下方法做一些處理工作:
/** 當(dāng)對 UICollectionView 進行刪除/插入的更新時:
* 1、首先調(diào)用此方法,讓布局對象知道將要發(fā)生什么變化
* 2、之后,會進行額外的調(diào)用,以收集將進行動畫化的插入、刪除和移動項的布局信息。
* @param updateItems 移動到新索引路徑的元素
*
* @note 它將在調(diào)用下面的 initial/final 布局屬性方法之前調(diào)用,以使布局有機會對插入和刪除布局屬性進行批處理計算。
*/
- (void)prepareForCollectionViewUpdates:(NSArray<UICollectionViewUpdateItem *> *)updateItems;
/** 更新后在動畫塊Block內(nèi)調(diào)用,執(zhí)行任何額外的動畫清理工作;
* 用于執(zhí)行所有插入、刪除和移動動畫的動畫塊中調(diào)用,以便根據(jù)需要使用此方法創(chuàng)建額外的動畫。
* 也可以使用它來執(zhí)行與管理布局對象的狀態(tài)信息相關(guān)的最后時刻的任務(wù);
*/
- (void)finalizeCollectionViewUpdates;
/** 檢索要添加到布局中的補充\裝飾視圖的索引路徑數(shù)組
* @param elementKind 視圖的類型
* @return 新的補充\裝飾視圖的位置;如果不想添加任何視圖,可以返回一個空數(shù)組。
* @discussion 向UICollectionView添加單元格或 sections 時,將調(diào)用該方法,促使布局對象有機會添加新的補充\裝飾視圖來補充添加的內(nèi)容。
* 在調(diào)用 -prepareForCollectionViewUpdates: 和 -finalizeCollectionViewUpdates 之間調(diào)用這個方法
*/
- (NSArray<NSIndexPath *> *)indexPathsToInsertForSupplementaryViewOfKind:(NSString *)elementKind API_AVAILABLE(ios(7.0));
- (NSArray<NSIndexPath *> *)indexPathsToInsertForDecorationViewOfKind:(NSString *)elementKind API_AVAILABLE(ios(7.0));
/** 檢索表示要刪除的補充視圖的索引路徑數(shù)組。
* 一個NSIndexPath對象數(shù)組,表示你想要刪除的補充視圖,或者如果你不想刪除任何給定類型的視圖,一個空數(shù)組。
* 每當(dāng)您在集合視圖中刪除單元格或部分時,集合視圖將調(diào)用此方法。實現(xiàn)此方法使布局對象有機會刪除不再需要的任何補充視圖。
* 集合視圖在調(diào)用prepareForCollectionViewUpdates:和finalizeCollectionViewUpdates之間調(diào)用這個方法。
*/
- (NSArray<NSIndexPath *> *)indexPathsToDeleteForSupplementaryViewOfKind:(NSString *)elementKind API_AVAILABLE(ios(7.0));
/** 檢索表示要刪除的裝飾視圖的索引路徑數(shù)組。
* @return 一個NSIndexPath對象數(shù)組,表示要刪除的裝飾視圖;如果不想刪除任何給定類型的視圖,則使用空數(shù)組。
* @discussion 每當(dāng)您在集合視圖中刪除單元格或部分時,集合視圖將調(diào)用此方法。實現(xiàn)此方法使布局對象有機會刪除不再需要的任何裝飾視圖。
集合視圖在調(diào)用prepareForCollectionViewUpdates:和finalizeCollectionViewUpdates之間調(diào)用這個方法。
*/
- (NSArray<NSIndexPath *> *)indexPathsToDeleteForDecorationViewOfKind:(NSString *)elementKind API_AVAILABLE(ios(7.0));
/** 當(dāng)項目位于 UICollectionView 邊界中的指定位置時,檢索該項的索引路徑
* @param previousIndexPath 項的前一個索引路徑
* @param position 在 UICollectionView 中指定位置
* @return 與 UICollectionView 中指定位置對應(yīng)的索引路徑
* @discussion 在項目拖動期間,將 UICollectionView 中的點映射到對應(yīng)于這些點位置的索引路徑。
* 默認(rèn)實現(xiàn)搜索指定位置的現(xiàn)有單元格,并返回該單元格的索引路徑。
* 如果在同一位置有多個單元格,該方法將返回最上面的單元格:即 zIndex 值最大的單元格
* 重寫此方法,可以更改索引路徑的確定方式。例如,返回具有 zIndex 最低值的單元格索引路徑。
* @note 如果覆蓋此方法,則不需要調(diào)用super。
*/
- (NSIndexPath *)targetIndexPathForInteractivelyMovingItem:(NSIndexPath *)previousIndexPath withPosition:(CGPoint)position API_AVAILABLE(ios(9.0));
2.3、使布局無效:優(yōu)化布局性能
在自定義布局時,可以通過只取消布局中實際更改的部分來提高性能:
- 當(dāng)更改項時,調(diào)用
-invalidateLayout方法強制將UICollectionView重新計算它的所有布局信息并重新應(yīng)用它; - 一個更好的解決方案是只重新計算已更改的布局信息,這正是無效上下文允許您做的事情。
無效上下文允許您指定布局的哪些部分發(fā)生了更改, 然后,布局對象可以使用該信息來最小化它重新計算的數(shù)據(jù)量。
要自定義無效上下文,需要子類化 UICollectionViewLayoutInvalidationContex:在子類中,定義表示布局?jǐn)?shù)據(jù)中可以獨立重新計算的部分的自定義屬性。
當(dāng)你需要在運行時使你的布局失效時,創(chuàng)建一個無效上下文子類的實例,根據(jù)改變的布局信息配置自定義屬性,并將該對象傳遞到你的布局的 -invalidateLayoutWithContext:方法,該方法的自定義實現(xiàn)可以使用invalidation 上下文中的信息來僅重新計算已更改的布局部分。
還應(yīng)該重寫invalidationContextClass方法并返回自定義類。
/** 使當(dāng)前布局失效并觸發(fā)布局更新
* @discussion 可以在任何時候調(diào)用此方法來更新布局信息;
* 異步使布局無效,并立即返回;因此,可以從相同的代碼塊多次調(diào)用此方法,而不會觸發(fā)多次布局更新;
* 實際的布局更新發(fā)生在下一個視圖布局更新周期中;
* @note 子類在重寫時必須始終調(diào)用super。
*/
- (void)invalidateLayout;
/** 根據(jù)提供的上下文信息使當(dāng)前部分布局無效
* @param context 上下文對象,指示要刷新布局的哪些部分
* @discussion 該方法默認(rèn)使用 UICollectionViewLayoutInvalidationContext 類的基本屬性優(yōu)化布局過程。
* 如果自定義上下文對象,需要重寫此方法并將上下文對象的任何自定義屬性應(yīng)用于布局計算
* @note 子類在重寫時必須始終調(diào)用super。
*/
- (void)invalidateLayoutWithContext:(UICollectionViewLayoutInvalidationContext *)context API_AVAILABLE(ios(7.0));
/** 如果自定義一個 UICollectionViewLayoutInvalidationContext 的子類提高布局更新的性能,
* 需要在 UICollectionViewLayout 的子類中調(diào)用該方法返回 Context 的子類
*/
@property(class, nonatomic, readonly) Class invalidationContextClass API_AVAILABLE(ios(7.0));
/** 詢問布局對象 滑動 CollectionView 時 是否需要更新布局
* @newBounds 滑動 UICollectionView 停止時的新邊界
* @return 如果需要更新布局,則返回YES;默認(rèn)返回NO,不需要更改布局;
* @discussion 如果滑動 UICollectionView 并且返回YES,那么通過調(diào)用 -invalidateLayoutWithContext: 使布局無效;
*/
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;
/** 檢索 UICollectionView.bounds 更改時對應(yīng)部分的上下文對象
* @newBounds UICollectionView 的新邊界
* @return 描述需要更改部分的上下文對象;不需更改返回nil;
* @discussion 重寫此方法創(chuàng)建和配置自定義 UICollectionViewLayoutInvalidationContext 以響應(yīng)邊界更改;
* 如果重寫此方法,首先調(diào)用super以獲得要返回的無效上下文對象;然后設(shè)置任何自定義屬性并返回它;
*/
- (UICollectionViewLayoutInvalidationContext *)invalidationContextForBoundsChange:(CGRect)newBounds API_AVAILABLE(ios(7.0));
/** 詢問布局對象:單元格自動調(diào)整大小,是否需要布局更新
* @param preferredAttributes 單元格的 -preferredLayoutAttributesFittingAttributes: 方法返回的布局屬性
* @param originalAttributes 布局對象最初為單元格建議的屬性;
* @return 如果布局應(yīng)該無效,則返回 YES ;默認(rèn)返回 NO,如果不應(yīng)該無效;
* @discussion 當(dāng) UICollectionView 包含自調(diào)整大小的單元格時,單元格可以在應(yīng)用這些屬性之前修改它們自己的布局屬性;
* 當(dāng)單元格提供一組不同的屬性時,調(diào)用該方法確定單元格的更改是否需要布局更新;
*/
- (BOOL)shouldInvalidateLayoutForPreferredLayoutAttributes:(UICollectionViewLayoutAttributes *)preferredAttributes withOriginalAttributes:(UICollectionViewLayoutAttributes *)originalAttributes API_AVAILABLE(ios(8.0));
/** 檢索上下文對象,該對象標(biāo)識為響應(yīng)動態(tài)單元格更改而應(yīng)更改的布局部分
* @param preferredAttributes 單元格的 -preferredLayoutAttributesFittingAttributes: 方法返回的布局屬性
* @param originalAttributes 布局對象最初為單元格建議的屬性;
* @return 無效上下文,其中包含關(guān)于需要對布局進行哪些更改的信息。
* @discussion 重寫該方法在返回上下文之前,調(diào)用super以便父類可以執(zhí)行對象的基本配置,還可以執(zhí)行附加配置。
*/
- (UICollectionViewLayoutInvalidationContext *)invalidationContextForPreferredLayoutAttributes:(UICollectionViewLayoutAttributes *)preferredAttributes withOriginalAttributes:(UICollectionViewLayoutAttributes *)originalAttributes API_AVAILABLE(ios(8.0));
/** 檢索上下文對象,該對象標(biāo)識在布局中交互移動的項
* @param targetIndexPaths 正在移動的項的當(dāng)前位置
* @param targetPosition 項的目的點
* @param previousIndexPaths 要移動的項以前位置
* @param previousPosition 項的原始點
* @return 包含關(guān)于需要對布局進行哪些更改的信息。
* @discussion 布局對象使用此方法在進行一個或多個項的交互式移動時檢索上下文。
*/
- (UICollectionViewLayoutInvalidationContext *)invalidationContextForInteractivelyMovingItems:(NSArray<NSIndexPath *> *)targetIndexPaths withTargetPosition:(CGPoint)targetPosition previousIndexPaths:(NSArray<NSIndexPath *> *)previousIndexPaths previousPosition:(CGPoint)previousPosition API_AVAILABLE(ios(9.0));
/** 檢索上下文對象,該對象標(biāo)識已移動的項
* @param indexPaths 項的最終位置。對于已取消的交互,這些索引路徑對應(yīng)于項的原始索引路徑。
* @param previousIndexPaths 項的原始位置。包含在移動序列期間集合視圖報告的最后一組索引路徑。
* @param movementCancelled 指示移動是否成功結(jié)束或取消的布爾值。
* @return 包含關(guān)于需要對布局進行哪些更改的信息
* @discussion 當(dāng)一個或多個項的交互式移動結(jié)束時,布局對象使用此方法檢索無效上下文,原因可能是移動成功,也可能是用戶取消了該移動。
*/
- (UICollectionViewLayoutInvalidationContext *)invalidationContextForEndingInteractiveMovementOfItemsToFinalIndexPaths:(NSArray<NSIndexPath *> *)indexPaths previousIndexPaths:(NSArray<NSIndexPath *> *)previousIndexPaths movementCancelled:(BOOL)movementCancelled API_AVAILABLE(ios(9.0));
2.4、協(xié)調(diào)動畫變化
/** 在顯示單元格的新邊界之前,UICollectionView 在動畫塊內(nèi)的邊界發(fā)生改變時調(diào)用
* 為視圖邊界的動畫更改或 Item 的插入或刪除準(zhǔn)備布局對象
* @param oldBounds UICollectionView 的當(dāng)前邊界
* @discussion 對 UICollectionView.bounds 執(zhí)行任何動畫更改之前或在動畫插入或刪除項之前調(diào)用此方法。
* 此方法使布局對象有機會執(zhí)行為這些動畫更改準(zhǔn)備所需的任何計算。
* 具體來說,使用此方法計算插入或刪除項的初始位置或最終位置,以便在請求時返回這些值。
* 還可以使用此方法執(zhí)行其他動畫 : 創(chuàng)建的任何動畫都被添加到用于處理插入、刪除和邊界更改的動畫塊中。
*/
- (void)prepareForAnimatedBoundsChange:(CGRect)oldBounds;
/** 在對 UICollectionView.bounds 進行任何動畫更改或在插入或刪除項之后清理
* @discussion 以動畫更改 UICollectionView.bounds 后或在動畫插入或刪除項后調(diào)用此方法。在動畫塊內(nèi)調(diào)用;
* 此方法使布局對象有機會執(zhí)行與這些操作相關(guān)的任何清理。
*/
- (void)finalizeAnimatedBoundsChange;
2.5、布局之間的過渡
UICollectionView 在傳入和傳出布局的布局過渡動畫之前調(diào)用這些方法
/** 告知布局對象,它將作為 UICollectionView 的布局被刪除
* 過渡動畫前將要刪除舊的Layout
* @param newLayout 過渡動畫結(jié)束時要使用的新布局對象。使用此對象根據(jù)最終的布局對象提供不同的起始屬性。
* @discussion 在執(zhí)行布局轉(zhuǎn)換之前,UICollectionView 調(diào)用此方法,以便布局對象可以執(zhí)行生成布局屬性所需的任何初始計算
*/
- (void)prepareForTransitionToLayout:(UICollectionViewLayout *)newLayout API_AVAILABLE(ios(7.0));
/** 告知布局對象準(zhǔn)備安裝為UICollectionView的布局
* @param oldLayout 在轉(zhuǎn)換開始時安裝在集合視圖中的布局對象。您可以使用此對象根據(jù)開始布局對象提供不同的結(jié)束屬性。
* @discussion 在執(zhí)行布局轉(zhuǎn)換之前,集合視圖調(diào)用此方法,以便您的布局對象可以執(zhí)行生成布局屬性所需的任何初始計算。
*/
- (void)prepareForTransitionFromLayout:(UICollectionViewLayout *)oldLayout API_AVAILABLE(ios(7.0));
/** 告訴布局對象在發(fā)生過渡動畫之前執(zhí)行最后的步驟
* @discussion 集合視圖在收集了執(zhí)行從一個布局到另一個布局轉(zhuǎn)換所需的所有布局屬性之后調(diào)用此方法。
* 可以使用這個方法來清理任何由 -prepareForTransitionFromLayout: 或 -prepareForTransitionToLayout: 方法的實現(xiàn)創(chuàng)建的數(shù)據(jù)結(jié)構(gòu)或緩存。
*/
- (void)finalizeLayoutTransition API_AVAILABLE(ios(7.0));
2.6、注冊裝飾視圖
/** 為布局對象注冊一個裝飾視圖
* @param viewClass 要用于補充視圖的類;如果想取消裝飾視圖的注冊,可以將 viewClass 指定 nil
* @param decorationViewKind 裝飾視圖的元素類型;使用此字符串來區(qū)分布局中具有不同的裝飾視圖;不能為nil,也不能為空字符串;
* @discussion 裝飾視圖為部分或整個UICollectionView提供視覺裝飾,但不與UICollectionView的數(shù)據(jù)源提供的數(shù)據(jù)綁定。
* 不需要顯式地創(chuàng)建裝飾視圖。注冊一個裝飾視圖后,由布局對象決定何時需要裝飾視圖,并從其 -layoutAttributesForElementsInRect: 方法中返回相應(yīng)的布局屬性。
* 對于指定裝飾視圖的布局屬性,UICollectionView 創(chuàng)建(或重用)視圖并根據(jù)注冊信息自動顯示它。
*/
- (void)registerClass:(nullable Class)viewClass forDecorationViewOfKind:(NSString *)elementKind;
- (void)registerNib:(nullable UINib *)nib forDecorationViewOfKind:(NSString *)elementKind;
2.7、支持從右到左的布局
UICollectionView 的默認(rèn)排列順序是從左到右,但是有時候需求可能從右到左排列。這時重寫下述方法:
/** 布局排列方向,默認(rèn)為 從左到右
* 重寫該方法,可以實現(xiàn)從右到左排列
* <ul> UIUserInterfaceLayoutDirection 的枚舉值:指定用戶界面的方向流。
* <li> UIUserInterfaceLayoutDirectionLeftToRight 布局方向從左到右
* <li> UIUserInterfaceLayoutDirectionRightToLeft 布局方向從右到左
* 當(dāng)使用本地化(如阿拉伯語或希伯來語)運行時,這個值是合適的,因為用戶界面布局的原點應(yīng)該位于坐標(biāo)系統(tǒng)的右邊緣
* </ul>
*/
@property (nonatomic, readonly) UIUserInterfaceLayoutDirection developmentLayoutDirection;
/** 是否在適當(dāng)?shù)臅r候自動翻轉(zhuǎn)水平坐標(biāo)系統(tǒng),默認(rèn)為NO
* 如果子類的返回 YES,UICollectionView 顯示這個布局將確保它的邊界。原點總是在前沿,如果需要,水平翻轉(zhuǎn)它的坐標(biāo)系統(tǒng)。
* 當(dāng)使用從左到右的布局時,布局信息會自動匹配集合視圖的自然坐標(biāo)系統(tǒng)。
* 但是,當(dāng)用戶的語言具有從右到左的方向時,提供的布局信息仍然基于集合視圖的自然坐標(biāo)系統(tǒng)。
* 這種差異會導(dǎo)致使用相反方向的語言出現(xiàn)布局問題。
* 將該值設(shè)置為YES時,集合視圖會自動翻轉(zhuǎn)其水平坐標(biāo)系統(tǒng)的方向,以匹配當(dāng)前語言。
* 翻轉(zhuǎn)水平坐標(biāo)系統(tǒng)可以有效地翻轉(zhuǎn)現(xiàn)有的布局信息,從而得到更美觀的布局。
*/
@property(nonatomic, readonly) BOOL flipsHorizontallyInOppositeLayoutDirection;
3、應(yīng)用
| 左\右對齊 | 瀑布流 |
|---|---|
![]() 左\右對齊.gif
|
![]() 瀑布流.png
|
| 卡片覆蓋 | 卡片輪轉(zhuǎn)效果 |
![]() 卡片覆蓋.gif
|
![]() 卡片輪轉(zhuǎn)效果.gif
|
| 小說閱讀器:覆蓋翻頁 | |
![]() 小說閱讀器:覆蓋翻頁.gif
|




