簡介
- 繼承自 UIScrowView
- 從 iOS 6 開始引入使用的
- Cell 只能通過注冊來確定重用標識符
- 每個格子都是個
UICollectionViewCell
每行顯示多少個 Cell,取決于UICollectionView
的寬度 能容納多少 Cell
UICollectionView 和 UITableView 的比較
- UITableViewController 的
self.view == self.tableview;
UICollectionViewController 的self.view != self.collectionView;
- UITableView 的滾動方式只能是垂直方向
UICollectionView 既可以垂直滾動,也可以水平滾動
- UITableView 的 Cell 是系統自動布局的,不需要自定義
-
UICollectionView
的 Cell 必須自定義布局
在創建UICollectionView
的時候必須傳遞一個布局參數
系統提供并實現了一個布局樣式:UICollectionViewFlowLayout
流水布局
1. 組成結構
可見部分
-
UICollectionView
內容顯示的主視圖:類似于 UITableView -
UICollectionViewCell
用于展示內容的主體:對于不同的 Cell 可以指定不同的尺寸和內容 -
Supplementary View
附加視圖:可以理解為 UITableView 每個 Section 的 HeaderView 和 FooterView -
Decoration View
裝飾視圖:這是每個 section 的背景視圖,用于裝飾該 section
不可見部分
-
UICollectionViewLayout
用來處理cell在屏幕上的布局
使用一系列的代理方法在 UICollectionView 上約束 Cell 的擺放,而且布局效果可以在運行時,隨時改變
2. 自定義布局
布局的函數調用流程
- 白框代表 CollectionView 在布局時使用的方法
- 橙框代表 CollectionView 的狀態
- 綠框代表 CollectionView 的使用者調用的方法
Paste_Image.png
簡介
-
UICollectionViewLayout 「抽象類」
會對屏幕上的 Cells 進行組織布局
首先要繼承
- 繼承 UICollectionViewLayout 或 UICollectionViewFlowLayout 流水布局
- 如果 繼承
UICollectionViewLayout
,要實現切換布局功能時必須實現layoutAttributesForItemAtIndexPath:
方法 - 在
layoutAttributesForItemAtIndexPath:
方法中執行prepareLayout
方法的布局方式
- (nullable UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath;
I. 預先設置布局樣式
作用
-
prepareLayout
用來做一些初始化操作 -
prepareLayout
執行前,collectionView
相關的尺寸等已經確定下來,供prepareLayout
使用
// 注意:重寫本方法時,必須調用父類方法
- (void)prepareLayout;
II. 在給定矩形范圍內設置布局屬性
作用
- 當
collectionView
滾動時調用該方法 - 1 個 Cell 對應 1 個
UICollectionViewLayoutAttributes
對象 - 返回值
UICollectionViewLayoutAttributes
對象
決定了 Rect 范圍內 Cell 的布局方式「frame 等」
決定了 Supplementary View、Decoration View 的布局方式
// UICollectionViewLayoutAttributes 的屬性
@property (nonatomic) CGPoint center; // view 在 CollectionView 的坐標系統中的 中心
@property (nonatomic) CGRect frame; // view 在 CollectionView 的坐標系統中的 具體位置
@property (nonatomic) CGSize size; // view 的大小
@property (nonatomic) CGRect bounds; // view 的尺寸
@property (nonatomic) CGFloat alpha; // 透明度
@property (nonatomic) NSInteger zIndex; // 子視圖的層級「默認 0」
@property (nonatomic) CATransform3D transform3D; // 用來旋轉,縮放的屬性
@property (nonatomic) CGAffineTransform transform; // 用來形裝改變
@property (nonatomic, getter=isHidden) BOOL hidden; // view 是否隱藏「如果隱藏 view 可能會不產生」
// rect:和 collectionView 的坐標系一致,控制 collectionView 部分內容顯示在屏幕上的矩形大小
- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect;
III. 確保每次滾動時重新布局
作用
- 表示 collectionView 滾動時「顯示的范圍發生改變時」,是否廢棄當前的布局
- 一旦廢棄當前的布局,就會依次調用
prepareLayout
、layoutAttributesForElementsInRect:
方法
// 默認 返回 NO
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;
IV. 確定滾動結束后的布局
作用
- 滑動 collectionView 松開后調用
- 返回 collectionView 停止滾動時最終的偏移量
contentOffset
// proposedContentOffset:collectionView 停止滾動時最終的偏移量
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset;
// velocity:滾動速率,通過這個參數可以了解滾動的方向
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity;
3. 總體步驟
原理
- UICollectionView 向
UICollectionViewLayout
詢問布局
詢問時,layout 對象會創建UICollectionViewLayoutAttributes
實例 - 1 個
UICollectionViewLayoutAttributes
對象管理著 1 個對應的item layout
相關信息「一對一關系」
步驟
- 注冊 Cell「告訴 collectionView 將來創建那種標識的 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;
}
- 重寫 init 方法,創建布局參數「必須傳入 非空布局,否則會報錯」
// UICollectionViewFlowLayout 流水布局的內部成員屬性有以下:
@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; // 滾動方向「默認豎直方向」
@property (nonatomic) CGSize headerReferenceSize; // 每一組 header的大小
@property (nonatomic) CGSize footerReferenceSize; // 每一組 footer的大小
@property (nonatomic) UIEdgeInsets sectionInset; // UICollectionView 四周的內邊距
- (id)init {
// 流水布局
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.minimumLineSpacing = 10;
layout.sectionInset = UIEdgeInsetsMake(layout.minimumLineSpacing, 0, 0, 0);
return [super initWithCollectionViewLayout:layout];
}
- 實現數據源方法
@optional
// 返回每個組的 Cell 的數量「每個組的數量相同時使用」
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView;
@required
// 返回 給定組的 Cell 的數量
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section;
// 返回 給定組號和組中序號 的 Cell 對象
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;
- 實現代理方法「Optional」
@optional // 所有代理方法都是可選的
// 點擊了一個 Cell 后調用
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath;