概览 UITableView
是UIKit
视图类中极其重要的一个,我们与之打交道的频率也是极高的。在UIKit视图类中有一个类与UITableview
共享一套API设计,但相比UITableview
,该类的视图布局更加灵活复杂。这就是UICollectionView
。本篇的着重点也放在UICollectionView
灵活强大的视图布局上面。
UICollectionView结构 UICollectionView的结构可以分为两部分来看:
从数据和驱动角度能看到两部分:
dataSource:数据源,遵循UICollectionViewDataSource协议,负责向collectionView提供数据以及视图。同时,还负责处理cells、supplementary views的创建和配置工作。
delegate:代理,遵循UICollectionViewDelegate协议,负责管理item视图的选中高亮状态以及item的点击事件。
从视图角度能看到三部分:
Cells:在collection view的可视范围内负责展示数据的内容
Supplementary views:也是负责展示数据,但与cells不同,它无法被用户选中,类似于UITableview的header和footer
Decoration views:属于装饰性view,不与collectionView的数据产生联系,更像是另一类的Supplementary views。 注:Supplementary views、Decoration views必须是UICollectionReusableView的子类。
这些组成结构与UITableview
比较,并没有太大的区别,真正的区别在于UICollectionLayout
,这不仅是本篇笔记的着重点,也是UICollectionView的精髓。
UICollectionViewLayout UICollectionViewLayout
是一个抽象类,因此我们必须要继承并实现相关方法才能使用它。Layout的工作是确定Cells、supplementary views、decoration views在collectionView的bounds中的位置并且当collectionView需要时传递相关信息。collectionView根据传递过来的相关layout信息对views进行相应和处理以便能让他们在屏幕上能够显示出来。
UICollectionViewFlowLayout
是苹果提供的继承于UICollectionViewLayout
的子类。当你对layout的需求不是很复杂的时候,UICollectionViewFlowLayout
往往可以满足需求,并且实现也比较简单,这里就不再讨论,感兴趣的可以查阅相关文档UICollectionviewFlowLayout 。
自定义继承UICollectionViewLayout
的子类必须重写以下方法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- (void )prepareLayout
- (CGSize )collectionViewContentSize
- (NSArray *)layoutAttributesForElementsInRect:(CGRect )rect
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath )indexPath
- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString )kind atIndexPath:(NSIndexPath *)indexPath
- (UICollectionViewLayoutAttributes * )layoutAttributesForDecorationViewOfKind:(NSString )decorationViewKind atIndexPath:(NSIndexPath )indexPath
- (BOOL )shouldInvalidateLayoutForBoundsChange:(CGRect )newBounds
这些方法提供了collectionView在屏幕上展示内容所需要的基本布局信息。当collectionView中的数据发生改变并且items需要执行增删操作,collectionView会要求layout对象去更新layout布局信息。任何item被添加、移除、移动都必须更新它的布局信息来对应它正确的位置信息。当item被移动时,collectionView调用上面的方法来重新获取item更新后的布局属性,而item被插入或删除时,collectionView会调用不同的方法,也就是你需要重写的方法:1
2
3
4
5
6
7
8
9
10
11
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath;
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingDecorationElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)decorationIndexPath;
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingSupplementaryElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)elementIndexPath;
- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath;
- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingDecorationElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)decorationIndexPath;
- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingSupplementaryElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)elementIndexPath;
此外,你也可以重写prepareForCollectionViewUpdates:
方法来处理任何与布局相关的预处理操作,重写finalizeCollectionViewUpdates
方法来添加动画或者实现布局相关的任务。
UICollectionViewLayoutAttributes 重写的方法中涉及到一个类UICollectionViewLayoutAttributes
。该类负责管理collectionView中给定item的布局相关的属性。当collectionView需要时,便会要求layout对象创建该类的实例对象。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@interface UICollectionViewLayoutAttributes : NSObject <NSCopying , UIDynamicItem >
@property (nonatomic ) CGRect frame;
@property (nonatomic ) CGPoint center;
@property (nonatomic ) CGSize size;
@property (nonatomic ) CATransform3D transform3D;
@property (nonatomic ) CGRect bounds NS_AVAILABLE_IOS (7 _0);
@property (nonatomic ) CGAffineTransform transform NS_AVAILABLE_IOS (7 _0);
@property (nonatomic ) CGFloat alpha;
@property (nonatomic ) NSInteger zIndex;
@property (nonatomic , getter =isHidden) BOOL hidden;
@property (nonatomic , strong ) NSIndexPath *indexPath;
@property (nonatomic , readonly ) UICollectionElementCategory representedElementCategory;
@property (nonatomic , readonly , nullable ) NSString *representedElementKind;
+ (instancetype )layoutAttributesForCellWithIndexPath:(NSIndexPath *)indexPath;
+ (instancetype )layoutAttributesForSupplementaryViewOfKind:(NSString *)elementKind withIndexPath:(NSIndexPath *)indexPath;
+ (instancetype )layoutAttributesForDecorationViewOfKind:(NSString *)decorationViewKind withIndexPath:(NSIndexPath *)indexPath;
@end
可以看出,UICollectionViewLayoutAttributes
包含了Cell的frame、center、bounds等布局信息。
结语 相比于UITableview
,UICollectionview
布局的复杂程度要更复杂得多,能很好的写出一个很不容易。正是由于UICollectionview
布局的复杂性,我们更需要多去使用,在使用的过程中才能更好的理解UICollectionview
本身这套API,也更好地学习苹果设计类的灵活性。