Write in the first【写在最前】
UITableView 熟悉吧, UICollectionView 必须熟悉吧。
在WWDC2012
中的Introducing Collection Views
,苹果首次介绍了UICollectionView
,类似UITableView
的用法使人很容易接受,但强大的自定义布局,又使其相较于UITableView
有了选择它的更多理由,UITableView
中的表格只支持单排列表,没有办法支持网格列表模式,CollectionView
有着灵活的布局特性,这一点充分说明我们在学会UITableView
的基础上,再去学习推敲CollectionView
的必要性。
本篇文章主要从【UICollectionView
系统文件注解】学习总结。
在「时间 & 知识 」有限内,总结的文章难免有「未全、不足 」的地方,还望各位好友指出,以提高文章质量。
目录:
- UICollectionView概念
- UICollectionView基本组成
- UICollectionView层次结构
1.UICollectionView 继承于 UIScrollView
2.UICollectionViewDataSource数据源
3.UICollectionViewDelegate代理
4.UICollectionViewLayout自定义布局对象
5.UICollectionViewFlowLayout布局对象(默认)
6.UICollectionViewCell样式
7.UICollectionViewLayoutAttributes布局属性- UICollectionView与UITableView比较
- UICollectionView使用说明
- UICollectionView基本使用
- 自定义FlowLayout:水平滚动相册
- UICollectionView效果图
- 自定义FlowLayout:瀑布流
- UICollectionView.h 属性&方法
UICollectionView概念
本着好好学习,了解权威的目的,我们还是主动看官网的说明。
上图释义:管理有序的数据项集合和使用自定制的布局。
通俗点就是:UICollectionView 是一种新的数据展示方式,简单来说可以把他理解成多列的UITableView
,可以做九宫格布局的一种view
;
UICollectionView基本组成
注解:如上图:你看到的就是一个最简单的UICollectionView
,它包含:Cells
、Supplementary Views
、Decoration Views
。
Cells:用于展示内容的主体,
cell
的尺寸和内容可以各不相同。Supplementary Views:追加视图,类似于
UITableView
每个Seciton
的Header View
或者Footer View
,用来标记Section
的View
。Decoration Views:装饰视图,完全跟数据没有关系的视图,负责给
cell
或者supplementary Views
添加辅助视图用的,灵活性较强。不管多么复杂的
UIcollectionView
都是由着三个部件组成的。
UICollectionView层次结构
注解:
1、UICollectionView 继承于 UIScrollView
1 | NS_CLASS_AVAILABLE_IOS(6_0) @interface : UIScrollView |
2、UICollectionViewDataSource:主要管理视图数据源方面,告诉view
要显示些什么东西以及如何显示它们。
@required(必须)
123456789 | @protocol UICollectionViewDataSource <NSObject>@required- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section;// The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:/* (必须)设置每个区中【item的内容】,类似于UITableViewCell的设置 */- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath; |
@optional(可选)
123456789101112131415 | @optional(可选)/* (可选)设置容器视图有多少组Section,系统默认返回值为1 */- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView;// The view that is returned must be retrieved from a call to -dequeueReusableSupplementaryViewOfKind:withReuseIdentifier:forIndexPath:// 补充视图,这里可以充当区的头和尾,我们自己不实现的话,系统默认返回值为nil/* (可选)返回顶部视图和底部视图,通过kind参数分辨是设置顶部还是底部(补充视图) */- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath;/** (可选)询问是否指定的单元格项目是否可以移动到集合视图中的另一个位置,默认返回值为NO */- (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(9_0);/** (可选)将指定的单元格项目从一个位置移动到集合视图中的另一个位置 */- (void)collectionView:(UICollectionView *)collectionView moveItemAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath*)destinationIndexPath NS_AVAILABLE_IOS(9_0); |
3、UICollectionViewDelegate:主要管理于用户交互方面,提供一些样式的小细节。
@optional(可选)
123456789101112131415161718192021222324252627 | @protocol UICollectionViewDelegate <UIScrollViewDelegate>@optional// Methods for notification of selection/deselection and highlight/unhighlight events.// The sequence of calls leading to selection from a user touch is:// (when the touch begins)// 1. -collectionView:shouldHighlightItemAtIndexPath:// 2. -collectionView:didHighlightItemAtIndexPath://// (when the touch lifts)// 3. -collectionView:shouldSelectItemAtIndexPath: or -collectionView:shouldDeselectItemAtIndexPath:// 4. -collectionView:didSelectItemAtIndexPath: or -collectionView:didDeselectItemAtIndexPath:// 5. -collectionView:didUnhighlightItemAtIndexPath:/** 下面是和高亮有关的方法: */// cell点击时是否高亮,点击cell时的样式和点击后cell的样式- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath;// 手指按下高亮- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath;// 手指松开取消高亮- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath;/** 当前item是否可以点击 */- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath;/** 当前item是否取消点击 */- (BOOL)collectionView:(UICollectionView *)collectionView shouldDeselectItemAtIndexPath:(NSIndexPath *)indexPath; // called when the user taps on an already-selected item in multi-select mode |
事件的处理顺序如下:
1、手指按下:
shouldHighlightItemAtIndexPath
(如果返回YES则向下执行,否则执行到这里为止)。2、
didHighlightItemAtIndexPath
(高亮)。3、手指松开:
didUnhighlightItemAtIndexPath
(取消高亮)。4、
shouldSelectItemAtIndexPath
(如果返回YES
则向下执行,否则执行到这里为止)。5、
didSelectItemAtIndexPath
(执行选择事件)。
选中 和 取消选中
item
时 ,会触发的方法
1234 | /* 选中item时 ,会触发的方法 */- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath;/* 取消选中item时 ,会触发的方法 */- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath; |
- 补充视图(头部或尾部视图),显示 和 移除
12345678910111213 | /** 这两个方法分别是指定indexPath的cell将要显示出的时候调用, 和指定indexPath的头部或尾部视图view将要显示出来的时候调用 */- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0);- (void)collectionView:(UICollectionView *)collectionView willDisplaySupplementaryView:(UICollectionReusableView *)view forElementKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0);/** 这两个方法分别是指定indexPath的cell将要从collectionView中移除的的时候调用, 和指定indexPath的头部或尾部视图view将要collectionView中移除的时候调用 */- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath;- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingSupplementaryView:(UICollectionReusableView *)view forElementOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath; |
- 长按某
item
,弹出copy(复制)
和paste(粘贴)
的菜单相关。
12345678910 | // These methods provide support for copy/paste actions on cells.// All three should be implemented if any are./** 这些方法为是 复制/粘贴操作相关 *//** 是否弹出菜单,需要返回YES */- (BOOL)collectionView:(UICollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath;/** 是否可以弹出事件,使copy和paste有效 */- (BOOL)collectionView:(UICollectionView *)collectionView canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender;/** 对事件进行相应操作 */- (void)collectionView:(UICollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender; |
- 注册类型相关
1234567 | /** 注册要使用的cell对应的类型 */- (void)registerClass:(nullable Class)cellClass forCellWithReuseIdentifier:(NSString *)identifier;- (void)registerNib:(nullable UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier;/** 注册要使用的补充视图(HeaderView 和 FooterView)对应的类型 */- (void)registerClass:(nullable Class)viewClass forSupplementaryViewOfKind:(NSString *)elementKind withReuseIdentifier:(NSString *)identifier;- (void)registerNib:(nullable UINib *)nib forSupplementaryViewOfKind:(NSString *)kind withReuseIdentifier:(NSString *)identifier; |
- 复用队列
123 | /** 复用队列 */- (__kindof UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath;- (__kindof UICollectionReusableView *)dequeueReusableSupplementaryViewOfKind:(NSString *)elementKind withReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath; |
- 动态修改当前的Item 和 Section
1234567891011121314151617181920212223 | // These methods allow dynamic modification of the current set of items in the collection view/** 这些方法允许动态修改当前的Item 和 Section */// 插入Section- (void)insertSections:(NSIndexSet *)sections;// 删除Section- (void)deleteSections:(NSIndexSet *)sections;// 刷新Section- (void)reloadSections:(NSIndexSet *)sections;// 移动Section- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection;// 插入Item- (void)insertItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths;// 删除Item- (void)deleteItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths;// 刷新Item- (void)reloadItemsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths;// 移动Item- (void)moveItemAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath;/** 同样可以进行批量操作 */- (void)performBatchUpdates:(void (^ __nullable)(void))updates completion:(void (^ __nullable)(BOOL finished))completion; // allows multiple insert/delete/reload/move calls to be animated simultaneously. Nestable. |
- 其它属性 和 方法相关
1234567891011121314 | /** 预加载 */@property (nonatomic, getter=isPrefetchingEnabled) BOOL prefetchingEnabled NS_AVAILABLE_IOS(10_0);/** 允许选择 */@property (nonatomic) BOOL allowsSelection; // default is YES/** 允许多个选择 */@property (nonatomic) BOOL allowsMultipleSelection; // default is NO/** 全局刷新 */- (void)reloadData; // discard the dataSource and delegate data and requery as necessary/** 布局动画 */- (void)setCollectionViewLayout:(UICollectionViewLayout *)layout animated:(BOOL)animated; // transition from one layout to another- (void)setCollectionViewLayout:(UICollectionViewLayout *)layout animated:(BOOL)animated completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0); |
4、UICollectionViewLayout:自定义布局,它负责了将各个cell
、Supplementary View
和Decoration Views
进行组织。
UICollectionViewLayout 是UICollectionView
特有的,是UICollectionView
的精髓所在,它负责将每个cell
、supplementary view
、decoration view
进行组合,为它们设置各自的属性,包括:位置、大小、透明度、层级关系、形状等。UICollectionViewLayout
决定了,UICollectionView
是如何显示在界面上,从UICollectionView
初始化必须要一个UICollectionViewLayout
也可以看得出来,Layout
对于UICollectionView
的最要性。
自定义布局:只要了解5个方法(重写它方法,扩展功能)
12345678910111213141516171819202122232425 | /** 什么时候调用:collectionView第一次布局,collectionView刷新的时候也会调用 作用:计算cell的布局,条件:ell的位置是固定不变的. */- (void)prepareLayout;/** 作用:指定一段区域给你这段区域cell的尺寸(可以一次性返回所有cell尺寸,也可以每隔一个距离返回cell) 系统传递过来一个区域rect,我们需要返回在该区域中的item的位置信息 返回的是一个数组,数组中包含UICollectionViewLayoutAttributes 对象 */- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect; // return an array layout attributes instances for all the views in the given rect// 在滚动的时候是否允许刷新(Invalidate)布局- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds; // return YES to cause the collection view to requery the layout for geometry information/** 什么时候调用:用户手指一松开就会调用 作用:确定最终偏移量 */- (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- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset NS_AVAILABLE_IOS(7_0); // a layout can return the content offset to be applied during transition or update animations/** 由于UICollectionVeiw继承自UIScrollView,所以需要重写该函数,告诉contentSize大小 */- (CGSize)collectionViewContentSize; |
5、UICollectionViewFlowLayout:主要管理布局信息方面,Apple
为我们提供了一个最简单可能也是最常用的默认layout
对象,UICollectionViewFlowLayout
。Flow Layout
简单说是一个直线对齐的layout
。
- 我们来了解
UICollectionViewFlowLayout
它内部常用的属性:
12345678910111213141516171819202122232425262728 | NS_CLASS_AVAILABLE_IOS(6_0) @interface UICollectionViewFlowLayout : UICollectionViewLayout@property (nonatomic) CGFloat minimumLineSpacing; // 设置行之间的最小间距(竖直)@property (nonatomic) CGFloat minimumInteritemSpacing; // 设置2个item之间(列)的最小间隙(水平),@property (nonatomic) CGSize itemSize; // 设置item的大小/** 预设item大小 */@property (nonatomic) CGSize estimatedItemSize NS_AVAILABLE_IOS(8_0); // defaults to CGSizeZero - setting a non-zero size enables cells that self-size via -preferredLayoutAttributesFittingAttributes:/** 设置滚动方向,默认是竖直滚动 V */@property (nonatomic) UICollectionViewScrollDirection scrollDirection; // default is UICollectionViewScrollDirectionVerticaltypedef NS_ENUM(NSInteger, UICollectionViewScrollDirection) { UICollectionViewScrollDirectionVertical, // 默认是竖直滚动 UICollectionViewScrollDirectionHorizontal // 水平滚动};// 设置滚动方向,/** 1.如果是垂直滚动,高度起作用,宽度忽略 / 2.如果是水平滚动,宽度期作用,高度忽略 */@property (nonatomic) CGSize headerReferenceSize; // 分组的头部视图的size大小@property (nonatomic) CGSize footerReferenceSize; // 分组的尾部视图的size大小@property (nonatomic) UIEdgeInsets sectionInset; // 设置区的内边距// Set these properties to YES to get headers that pin to the top of the screen and footers that pin to the bottom while scrolling (similar to UITableView).// 头部视图悬停设为YES@property (nonatomic) BOOL sectionHeadersPinToVisibleBounds NS_AVAILABLE_IOS(9_0);// 尾部视图悬停设为YES@property (nonatomic) BOOL sectionFootersPinToVisibleBounds NS_AVAILABLE_IOS(9_0);@end |
- 上面对
FlowLayout
的属性设置,当然代理方法中也有一一对应,UICollectionViewDelegateFlowLayout
常用方法:
1234567891011121314151617181920212223242526 | @protocol UICollectionViewDelegateFlowLayout <UICollectionViewDelegate>@optional/** 下面的代理方法是针对indexPath对应的item进行个性化设置 如果使用的是UICollectionViewFlowLayout布局,这些代理方法自动调用 *//** 设置指定indexPath的单元格的大小(itemSize) */- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;/** 设置分组中的每一个单元格的上下左右的空白距离(内边距) */- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;/** 设置分组中的单元格的行间距(竖直) */- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section;/** 设置每行中的item的(列)间距(水平) */- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section;/** 分组的头部视图的size大小,含义也是有滚动方向决定的 */- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section;/** 分组的尾部视图的size大小,含义也是有滚动方向决定的 */- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section;@end |
UIEdgeInsets sectionInset 内边距
大专栏 iOS UI控件详解—「UICollectionView综合视图」Cell的结构上相对比较简单。">6、UICollectionViewCell:相对于UItableViewCell
而言,UIcollectionViewCell
没有那么多样式。UIcollectionViewCell
不存在所谓的style
,也没有titleLabel
和内置的imageView
属性,UIcollectionViewCell
的结构上相对比较简单。
cell
:本身作为的View
,这里应该就是UICollectionReusableView
backgroundView
:用作cell
背景的视图,设置背景图片等。selectedBackgroundView
:cell
被选中的背景视图contentView
:内容视图,自定义的cell
时应该将内容放在这个View上补充:
UIcollectionView
有一个小细节:被选中的cell
的自动变化,所有的cell
中的子View
,也包括contentView
中的子View
,当cell
被选中是,会自动去查找view
是否有被选中状态下的改变,如果在contentView
中有一个imageView
的selected
和normal
状态下的图片是不同的,那么选中cell
这张图片也会从normal
变成selected
,不需要添加代码。
7、UICollectionViewLayoutAttributes 布局属性:
在了解这个类之前,我们得先疏通一下,UIcollectionView
的布局方式,首先我们之前一直提,UIcollectionView
的初始化必须有一个UICollectionViewLayout
,也就是我们说的,必须要有一个布局格式样式,
那么一个UIcollectionView
有那么多的cell
、supplementary
View
、decoration View
,UIcollectionViewLayout
是如何进行布局显示的呢?
原来从UIcollectionViewLayout
开始加载内容的时候,便默默的做了很多事:首先是去调用 prepareLayout
准备布局,然后根据当前屏幕所处位置的合适rect
,得到每一个视图的UICollectionViewLayoutAttributes
属性,然后在把视图按UICollectionViewLayoutAttributes
中的属性描述设置视图具体的center
、size
等等,期间也会去调用其他方法去确定一些间距。所以UICollectionViewLayoutAttributes
是每个视图决定性的布局的属性。
12345678910111213141516 | NS_CLASS_AVAILABLE_IOS(6_0) @interface UICollectionViewLayoutAttributes : NSObject <NSCopying, UIDynamicItem>@property (nonatomic) CGRect frame; // 布局视图的frame简单明了@property (nonatomic) CGPoint center; // 视图中心点@property (nonatomic) CGSize size; // 视图尺寸@property (nonatomic) CATransform3D transform3D; // 这个属性可以用来做酷炫的3D动画@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; // default is 0 // 层级,数字越大,层级越高(最上面)@property (nonatomic, getter=isHidden) BOOL hidden; // As an optimization, UICollectionView might not create a view for items whose hidden attribute is YES@property (nonatomic, strong) NSIndexPath *indexPath; // 如果是cell有对应的indexPath// 视图标记,是cell还是supplementary View或者decoration View@property (nonatomic, readonly) UICollectionElementCategory representedElementCategory;@property (nonatomic, readonly, nullable) NSString *representedElementKind; // nil when representedElementCategory is UICollectionElementCategoryCell |
UICollectionView与UITableView比较
相同点:
都需要遵守
DataSource
和Delegate
,实现协议方法。待补充
不同点:
- 与
UITableView
的最大不同,布局交给了指定的UICollectionViewLayout
布局对象。
UICollectionView
的cell
使用必须先注册,使用出列的方式。UICollectionView
:Supplementary
补充视图需要先注册(这里可以充当区的头和尾)。待补充
- 与
UICollectionView 使用说明
说明:代码不重要,重要的是思维
创建
UICollectionView
必须要有布局参数flowLayout
;(采用懒加载)UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
cell
必须通过注册;registerClass: forCellWithReuseIdentifier:
自定义
Cell
,原因:系统cell
没有任何子控件;(添加子控件image
,label
)。@interface LNPhotoViewCell : UICollectionViewCell
FlowLayout
自定义(调整cell
尺寸,利用布局就做效果),原因:系统cell
中每个item
尺寸都一样;(继承flowLayout
或Layout
)。@interface LNFlowLayout : UICollectionViewFlowLayout
自定义布局: 只要了解5个方法(重写它方法,扩展功能)
1234567891011121314151617 | // 什么时候调用:collectionView第一次布局,collectionView刷新的时候也会调用// 作用:计算cell的布局,条件:ell的位置是固定不变的.- (void)prepareLayout;// 作用:指定一段区域给你这段区域cell的尺寸(可以一次性返回所有cell尺寸,也可以每隔一个距离返回cell)- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect;// 在滚动的时候是否允许刷新(Invalidate)布局- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;// 什么时候调用:用户手指一松开就会调用// 作用:确定最终偏移量- (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// 由于UICollectionVeiw继承自UIScrollView,所以需要重写该函数,告诉contentSize大小- (CGSize)collectionViewContentSize; |
UICollectionView基本使用
初始化
12345678910111213141516171819202122232425262728293031 | - (UICollectionView *)collectionView { if (_collectionView == nil) { UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; //sectionInset 设置区的内边距 layout.sectionInset = UIEdgeInsetsMake(20, 20, 20, 20); //设置2个item之间的最小间隙, layout.minimumInteritemSpacing = 10; //设置行之间的最小间距 layout.minimumLineSpacing = 10; //设置滚动方向,默认是垂直滚动 //layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; //如果是垂直滚动,高度起作用,宽度忽略 //如果是水平滚动,宽度期作用,高度忽略 layout.headerReferenceSize = CGSizeMake(50, 50); //设置footerView的大小 layout.footerReferenceSize = CGSizeMake(50, 50); _collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout]; _collectionView.backgroundColor = [UIColor whiteColor]; // 设置代理,遵守协议<UICollectionViewDataSource,UICollectionViewDelegate> _collectionView.dataSource = self; _collectionView.delegate = self; } return _collectionView;} |
注册UICollectionView
使用的cell
类型
12345678 | // 注册要使用的cell对应的类型[self.collectionView registerClass:[LNNumberCollectionViewCell class] forCellWithReuseIdentifier:cellID];// 注册要使用的HeaverView对应的类型[_collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeadViewId"];// 注册要使用的FooterView对应的类型[_collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"footViewId"]; |
实现协议UICollectionViewDataSource
12345678910111213141516171819202122 | #pragma mark - UICollectionViewDataSource// 多少区- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { return 3;}// 多少item- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return 20;}// item内容- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { LNNumberCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath]; cell.label.text = [NSString stringWithFormat:@"%ld",indexPath.item]; cell.photoImageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"%ld",indexPath.item + 1]]; //cell.backgroundColor = [UIColor grayColor]; return cell;} |
12345678910111213141516171819 | //和UITableView不同:补充视图需要先注册//Supplementary 补充视图,这里可以充当区的头和尾- (UICollectionReusableView*)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath{ if([kind isEqual:UICollectionElementKindSectionHeader]) { //指明是头 UICollectionReusableView *headView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HeadViewId" forIndexPath:indexPath]; headView.backgroundColor = [UIColor redColor]; return headView; } if ([kind isEqual:UICollectionElementKindSectionFooter]) { UICollectionReusableView *footView = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"footViewId" forIndexPath:indexPath]; footView.backgroundColor = [UIColor blueColor]; return footView; } return nil;} |
实现代理UICollectionViewDelegate
123456789101112131415161718 | // 点击item时触发- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{ NSLog(@"(第%ld-区,第%ld-item)",indexPath.section,indexPath.item); [collectionView cellForItemAtIndexPath:indexPath].backgroundColor = [UIColor redColor]; }// 当前item是否可以点击- (BOOL) collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(nonnull NSIndexPath *)indexPath{ if (indexPath.row % 2) { return YES; } return NO;} |
1234567891011121314151617 | //cell点击时是否高亮,点击cell时的样式和点击后cell的样式- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath{ return YES;}- (void)collectionView:(UICollectionView *)collectionView didHighlightItemAtIndexPath:(NSIndexPath *)indexPath{ UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; cell.backgroundColor = [UIColor redColor];}- (void)collectionView:(UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath{ UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; cell.backgroundColor = [UIColor grayColor];} |
123456789101112131415161718192021222324252627282930313233 | // 长按某item,弹出copy和paste的菜单 (这些方法为是 复制/粘贴操作相关)- (BOOL)collectionView:(UICollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath{ return YES;}// 使copy和paste有效- (BOOL)collectionView:(UICollectionView *)collectionView canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender{ if ([NSStringFromSelector(action) isEqualToString:@"copy:"] || [NSStringFromSelector(action) isEqualToString:@"paste:"]) { return YES; } return NO;}//- (void)collectionView:(UICollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(nullable id)sender{ if([NSStringFromSelector(action) isEqualToString:@"copy:"]) {// NSLog(@"-------------执行拷贝-------------"); [_collectionView performBatchUpdates:^{ [_section0Array removeObjectAtIndex:indexPath.row]; [_collectionView deleteItemsAtIndexPaths:@[indexPath]]; } completion:nil]; } else if([NSStringFromSelector(action) isEqualToString:@"paste:"]) { NSLog(@"-------------执行粘贴-------------"); }} |
布局对象UICollectionViewDelegateFlowLayout
123456789101112131415161718192021222324252627282930 | #pragma mark - UICollectionViewDelegateFlowLayout//下面的代理方法是针对indexPath对应的item进行个性化设置//如果使用的是UICollectionViewFlowLayout布局,这些代理方法自动调用- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{ // indexPath.item 指定第几个cell// NSInteger item = indexPath.item;// if (item % 3 == 1) {// return CGSizeMake(100, 150);// }// return CGSizeMake(100, 200); return CGSizeMake(100, 150);}/** 设置分组中的每一个单元格的上下左右的空白距离(内边距) */- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;/** 设置分组中的单元格的行间距(竖直) */- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section;/** 设置每行中的item的(列)间距(水平) */- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section;/** 分组的头部视图的size大小,含义也是有滚动方向决定的 */- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section;/** 分组的尾部视图的size大小,含义也是有滚动方向决定的 */- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section; |
自定义FlowLayout:水平滚动相册
核心代码如下:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061 | // 作用:指定一段区域给你这段区域cell的尺寸(可以一次性返回所有cell尺寸,也可以每隔一个距离返回cell)// 缩放- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect { // 设置cell尺寸 => UICollectionViewLayoutAttributes // 越靠近中心点,距离越小,缩放越大 // 求cell与中心点距离 // 1.获取当前显示cell的布局 NSArray *attrs = [super layoutAttributesForElementsInRect:self.collectionView.bounds]; for (UICollectionViewLayoutAttributes *attr in attrs) { // 2.计算中心点距离 CGFloat delta = fabs((attr.center.x - self.collectionView.contentOffset.x) - self.collectionView.bounds.size.width * 0.5); // 3.计算比例 CGFloat scale = 1 - delta / (self.collectionView.bounds.size.width * 0.5) * 0.25; // 4.缩放 attr.transform = CGAffineTransformMakeScale(scale, scale); } return attrs;}// 什么时候调用:// 作用:确定最终偏移量// 定位:距离中心点越近,这个cell最终展示到中心点- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity { // 最终偏移量 CGPoint targetP = [super targetContentOffsetForProposedContentOffset:proposedContentOffset withScrollingVelocity:velocity]; CGFloat collectionW = self.collectionView.bounds.size.width; // 1.获取最终显示的区域 CGRect targetRect = CGRectMake(targetP.x, 0, collectionW, MAXFLOAT); // 2.获取最终显示的cell NSArray *attrs = [super layoutAttributesForElementsInRect:targetRect]; // 3.获取最小间距 CGFloat minDelta = MAXFLOAT; for (UICollectionViewLayoutAttributes *attr in attrs) { // 获取距离中心点的距离,注意:应该用最终的x CGFloat delta = (attr.center.x - targetP.x) - self.collectionView.bounds.size.width * 0.5; if (fabs(delta) < fabs(minDelta)) { minDelta = delta; } } // 移动间距 targetP.x += minDelta; if (targetP.x < 0) { targetP.x = 0; } // 获取collectionView偏移量// NSLog(@"%@ %@",NSStringFromCGPoint(targetP),NSStringFromCGPoint(self.collectionView.contentOffset)); return targetP;} |
附图:
期待
- 如果在阅读过程中遇到 error || new ideas,希望你能 messages 我,我会及时改正谢谢。
- 点击右上角的 喜欢 和 订阅Rss 按钮,可以收藏本仓库,并在 Demo 更新时收到邮件通知。
来源:https://www.cnblogs.com/liuzhongrong/p/12408025.html