簡(jiǎn)介
- 繼承自 UIScrowView
- 從 iOS 6 開(kāi)始引入使用的
- Cell 只能通過(guò)注冊(cè)來(lái)確定重用標(biāo)識(shí)符
- 每個(gè)格子都是個(gè)
UICollectionViewCell
每行顯示多少個(gè) Cell,取決于UICollectionView的寬度 能容納多少 Cell
UICollectionView 和 UITableView 的比較
- UITableViewController 的
self.view == self.tableview;
UICollectionViewController 的self.view != self.collectionView; - UITableView 的滾動(dòng)方式只能是垂直方向
UICollectionView 既可以垂直滾動(dòng),也可以水平滾動(dòng)
- UITableView 的 Cell 是系統(tǒng)自動(dòng)布局的,不需要自定義
-
UICollectionView的 Cell 必須自定義布局
在創(chuàng)建UICollectionView的時(shí)候必須傳遞一個(gè)布局參數(shù)
系統(tǒng)提供并實(shí)現(xiàn)了一個(gè)布局樣式:UICollectionViewFlowLayout流水布局
1. 組成結(jié)構(gòu)
可見(jiàn)部分
-
UICollectionView內(nèi)容顯示的主視圖:類(lèi)似于 UITableView -
UICollectionViewCell用于展示內(nèi)容的主體:對(duì)于不同的 Cell 可以指定不同的尺寸和內(nèi)容 -
Supplementary View附加視圖:可以理解為 UITableView 每個(gè) Section 的 HeaderView 和 FooterView -
Decoration View裝飾視圖:這是每個(gè) section 的背景視圖,用于裝飾該 section
不可見(jiàn)部分
-
UICollectionViewLayout用來(lái)處理cell在屏幕上的布局
使用一系列的代理方法在 UICollectionView 上約束 Cell 的擺放,而且布局效果可以在運(yùn)行時(shí),隨時(shí)改變
2. 自定義布局
布局的函數(shù)調(diào)用流程
- 白框代表 CollectionView 在布局時(shí)使用的方法
- 橙框代表 CollectionView 的狀態(tài)
- 綠框代表 CollectionView 的使用者調(diào)用的方法

Paste_Image.png
簡(jiǎn)介
-
UICollectionViewLayout 「抽象類(lèi)」會(huì)對(duì)屏幕上的 Cells 進(jìn)行組織布局
首先要繼承
- 繼承 UICollectionViewLayout 或 UICollectionViewFlowLayout 流水布局
- 如果 繼承
UICollectionViewLayout,要實(shí)現(xiàn)切換布局功能時(shí)必須實(shí)現(xiàn)layoutAttributesForItemAtIndexPath:方法 - 在
layoutAttributesForItemAtIndexPath:方法中執(zhí)行prepareLayout方法的布局方式
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;
I. 預(yù)先設(shè)置布局樣式
作用
-
prepareLayout用來(lái)做一些初始化操作 -
prepareLayout執(zhí)行前,collectionView相關(guān)的尺寸等已經(jīng)確定下來(lái),供prepareLayout使用
// 注意:重寫(xiě)本方法時(shí),必須調(diào)用父類(lèi)方法
- (void)prepareLayout;
II. 在給定矩形范圍內(nèi)設(shè)置布局屬性
作用
- 當(dāng)
collectionView滾動(dòng)時(shí)調(diào)用該方法 - 1 個(gè) Cell 對(duì)應(yīng) 1 個(gè)
UICollectionViewLayoutAttributes對(duì)象 - 返回值
UICollectionViewLayoutAttributes對(duì)象
決定了 Rect 范圍內(nèi) Cell 的布局方式「frame 等」
決定了 Supplementary View、Decoration View 的布局方式
// UICollectionViewLayoutAttributes 的屬性
@property (nonatomic) CGPoint center; // view 在 CollectionView 的坐標(biāo)系統(tǒng)中的 中心
@property (nonatomic) CGRect frame; // view 在 CollectionView 的坐標(biāo)系統(tǒng)中的 具體位置
@property (nonatomic) CGSize size; // view 的大小
@property (nonatomic) CGRect bounds; // view 的尺寸
@property (nonatomic) CGFloat alpha; // 透明度
@property (nonatomic) NSInteger zIndex; // 子視圖的層級(jí)「默認(rèn) 0」
@property (nonatomic) CATransform3D transform3D; // 用來(lái)旋轉(zhuǎn),縮放的屬性
@property (nonatomic) CGAffineTransform transform; // 用來(lái)形裝改變
@property (nonatomic, getter=isHidden) BOOL hidden; // view 是否隱藏「如果隱藏 view 可能會(huì)不產(chǎn)生」
// rect:和 collectionView 的坐標(biāo)系一致,控制 collectionView 部分內(nèi)容顯示在屏幕上的矩形大小
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect;
III. 確保每次滾動(dòng)時(shí)重新布局
作用
- 表示 collectionView 滾動(dòng)時(shí)「顯示的范圍發(fā)生改變時(shí)」,是否廢棄當(dāng)前的布局
- 一旦廢棄當(dāng)前的布局,就會(huì)依次調(diào)用
prepareLayout、layoutAttributesForElementsInRect:方法
// 默認(rèn) 返回 NO
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;
IV. 確定滾動(dòng)結(jié)束后的布局
作用
- 滑動(dòng) collectionView 松開(kāi)后調(diào)用
- 返回 collectionView 停止?jié)L動(dòng)時(shí)最終的偏移量
contentOffset
// proposedContentOffset:collectionView 停止?jié)L動(dòng)時(shí)最終的偏移量
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset;
// velocity:滾動(dòng)速率,通過(guò)這個(gè)參數(shù)可以了解滾動(dòng)的方向
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity;
3. 總體步驟
原理
- UICollectionView 向
UICollectionViewLayout詢問(wèn)布局
詢問(wèn)時(shí),layout 對(duì)象會(huì)創(chuàng)建UICollectionViewLayoutAttributes實(shí)例 - 1 個(gè)
UICollectionViewLayoutAttributes對(duì)象管理著 1 個(gè)對(duì)應(yīng)的item layout相關(guān)信息「一對(duì)一關(guān)系」
步驟
- 注冊(cè) Cell「告訴 collectionView 將來(lái)創(chuàng)建那種標(biāo)識(shí)的 Cell」
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cellID"];
- 從緩存池中取出 Cell
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cellID" forIndexPath:indexPath];
return cell;
}
- 重寫(xiě) init 方法,創(chuàng)建布局參數(shù)「必須傳入 非空布局,否則會(huì)報(bào)錯(cuò)」
// UICollectionViewFlowLayout 流水布局的內(nèi)部成員屬性有以下:
@property (nonatomic) CGFloat minimumLineSpacing; // Cell 之間的垂直間距
@property (nonatomic) CGFloat minimumInteritemSpacing; // Cell 之間的水平間距
@property (nonatomic) CGSize itemSize; // Cell 的尺寸
@property (nonatomic) CGSize estimatedItemSize NS_AVAILABLE_IOS(8_0);
@property (nonatomic) UICollectionViewScrollDirection scrollDirection; // 滾動(dòng)方向「默認(rèn)豎直方向」
@property (nonatomic) CGSize headerReferenceSize; // 每一組 header的大小
@property (nonatomic) CGSize footerReferenceSize; // 每一組 footer的大小
@property (nonatomic) UIEdgeInsets sectionInset; // UICollectionView 四周的內(nèi)邊距
- (id)init {
// 流水布局
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.minimumLineSpacing = 10;
layout.sectionInset = UIEdgeInsetsMake(layout.minimumLineSpacing, 0, 0, 0);
return [super initWithCollectionViewLayout:layout];
}
- 實(shí)現(xiàn)數(shù)據(jù)源方法
@optional
// 返回每個(gè)組的 Cell 的數(shù)量「每個(gè)組的數(shù)量相同時(shí)使用」
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView;
@required
// 返回 給定組的 Cell 的數(shù)量
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section;
// 返回 給定組號(hào)和組中序號(hào) 的 Cell 對(duì)象
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;
- 實(shí)現(xiàn)代理方法「Optional」
@optional // 所有代理方法都是可選的
// 點(diǎn)擊了一個(gè) Cell 后調(diào)用
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath;