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
NS_CLASS_AVAILABLE_IOS (
6 _0)
@interface : UIScrollView
2、UICollectionViewDataSource:主要管理视图数据源方面,告诉view
要显示些什么东西以及如何显示它们。
1
2
3
4
5
6
7
8
9
@protocol UICollectionViewDataSource <NSObject >
@required
- (
NSInteger )collectionView:(
UICollectionView *)collectionView numberOfItemsInSection:(
NSInteger )section;
- (__kindof
UICollectionViewCell *)collectionView:(
UICollectionView *)collectionView cellForItemAtIndexPath:(
NSIndexPath *)indexPath;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@optional (可选)
- (
NSInteger )numberOfSectionsInCollectionView:(
UICollectionView *)collectionView;
- (
UICollectionReusableView *)collectionView:(
UICollectionView *)collectionView viewForSupplementaryElementOfKind:(
NSString *)kind atIndexPath:(
NSIndexPath *)indexPath;
- (
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:主要管理于用户交互方面,提供一些样式的小细节。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@protocol UICollectionViewDelegate <UIScrollViewDelegate >
@optional
- (
BOOL )collectionView:(
UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(
NSIndexPath *)indexPath;
- (
void )collectionView:(
UICollectionView *)collectionView didHighlightItemAtIndexPath:(
NSIndexPath *)indexPath;
- (
void )collectionView:(
UICollectionView *)collectionView didUnhighlightItemAtIndexPath:(
NSIndexPath *)indexPath;
- (
BOOL )collectionView:(
UICollectionView *)collectionView shouldSelectItemAtIndexPath:(
NSIndexPath *)indexPath;
- (
BOOL )collectionView:(
UICollectionView *)collectionView shouldDeselectItemAtIndexPath:(
NSIndexPath *)indexPath;
事件的处理顺序如下:
1、手指按下:shouldHighlightItemAtIndexPath
(如果返回YES则向下执行,否则执行到这里为止)。
2、didHighlightItemAtIndexPath
(高亮)。
3、手指松开:didUnhighlightItemAtIndexPath
(取消高亮)。
4、shouldSelectItemAtIndexPath
(如果返回YES
则向下执行,否则执行到这里为止)。
5、didSelectItemAtIndexPath
(执行选择事件)。
选中 和 取消选中 item
时 ,会触发的方法
1
2
3
4
- (
void )collectionView:(
UICollectionView *)collectionView didSelectItemAtIndexPath:(
NSIndexPath *)indexPath;
- (
void )collectionView:(
UICollectionView *)collectionView didDeselectItemAtIndexPath:(
NSIndexPath *)indexPath;
1
2
3
4
5
6
7
8
9
10
11
12
13
这两个方法分别是指定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(粘贴)
的菜单相关。
1
2
3
4
5
6
7
8
9
10
- (
BOOL )collectionView:(
UICollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(
NSIndexPath *)indexPath;
- (
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;
1
2
3
4
5
6
7
- (
void )registerClass:(
nullable Class)cellClass forCellWithReuseIdentifier:(
NSString *)identifier;
- (
void )registerNib:(
nullable
UINib *)nib forCellWithReuseIdentifier:(
NSString *)identifier;
- (
void )registerClass:(
nullable Class)viewClass forSupplementaryViewOfKind:(
NSString *)elementKind withReuseIdentifier:(
NSString *)identifier;
- (
void )registerNib:(
nullable
UINib *)nib forSupplementaryViewOfKind:(
NSString *)kind withReuseIdentifier:(
NSString *)identifier;
1
2
3
- (__kindof
UICollectionViewCell *)dequeueReusableCellWithReuseIdentifier:(
NSString *)identifier forIndexPath:(
NSIndexPath *)indexPath;
- (__kindof
UICollectionReusableView *)dequeueReusableSupplementaryViewOfKind:(
NSString *)elementKind withReuseIdentifier:(
NSString *)identifier forIndexPath:(
NSIndexPath *)indexPath;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- (
void )insertSections:(
NSIndexSet *)sections;
- (
void )deleteSections:(
NSIndexSet *)sections;
- (
void )reloadSections:(
NSIndexSet *)sections;
- (
void )moveSection:(
NSInteger )section toSection:(
NSInteger )newSection;
- (
void )insertItemsAtIndexPaths:(
NSArray <
NSIndexPath *> *)indexPaths;
- (
void )deleteItemsAtIndexPaths:(
NSArray <
NSIndexPath *> *)indexPaths;
- (
void )reloadItemsAtIndexPaths:(
NSArray <
NSIndexPath *> *)indexPaths;
- (
void )moveItemAtIndexPath:(
NSIndexPath *)indexPath toIndexPath:(
NSIndexPath *)newIndexPath;
- (
void )performBatchUpdates:(
void (^ __
nullable )(
void ))updates completion:(
void (^ __
nullable )(
BOOL finished))completion;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@property (
nonatomic ,
getter =isPrefetchingEnabled)
BOOL prefetchingEnabled
NS_AVAILABLE_IOS (
10 _0);
@property (
nonatomic )
BOOL allowsSelection;
@property (
nonatomic )
BOOL allowsMultipleSelection;
- (
void )reloadData;
- (
void )setCollectionViewLayout:(
UICollectionViewLayout *)layout animated:(
BOOL )animated;
- (
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个方法(重写它方法,扩展功能)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
什么时候调用:collectionView第一次布局,collectionView刷新的时候也会调用
作用:计算cell的布局,条件:ell的位置是固定不变的.
*/
- (
void )prepareLayout;
作用:指定一段区域给你这段区域cell的尺寸(可以一次性返回所有cell尺寸,也可以每隔一个距离返回cell)
系统传递过来一个区域rect,我们需要返回在该区域中的item的位置信息
返回的是一个数组,数组中包含UICollectionViewLayoutAttributes 对象
*/
- (
nullable
NSArray <__kindof
UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(
CGRect )rect;
- (
BOOL )shouldInvalidateLayoutForBoundsChange:(
CGRect )newBounds;
什么时候调用:用户手指一松开就会调用
作用:确定最终偏移量
*/
- (
CGPoint )targetContentOffsetForProposedContentOffset:(
CGPoint )proposedContentOffset withScrollingVelocity:(
CGPoint )velocity;
- (
CGPoint )targetContentOffsetForProposedContentOffset:(
CGPoint )proposedContentOffset
NS_AVAILABLE_IOS (
7 _0);
- (
CGSize )collectionViewContentSize;
5、UICollectionViewFlowLayout:主要管理布局信息方面,Apple
为我们提供了一个最简单可能也是最常用的默认layout
对象,UICollectionViewFlowLayout
。Flow Layout
简单说是一个直线对齐的layout
。
我们来了解UICollectionViewFlowLayout
它内部常用的属性:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
NS_CLASS_AVAILABLE_IOS (
6 _0)
@interface UICollectionViewFlowLayout : UICollectionViewLayout
@property (
nonatomic )
CGFloat minimumLineSpacing;
@property (
nonatomic )
CGFloat minimumInteritemSpacing;
@property (
nonatomic )
CGSize itemSize;
@property (
nonatomic )
CGSize estimatedItemSize
NS_AVAILABLE_IOS (
8 _0);
@property (
nonatomic )
UICollectionViewScrollDirection scrollDirection;
typedef
NS_ENUM (
NSInteger ,
UICollectionViewScrollDirection ) {
UICollectionViewScrollDirectionVertical ,
UICollectionViewScrollDirectionHorizontal
};
@property (
nonatomic )
CGSize headerReferenceSize;
@property (
nonatomic )
CGSize footerReferenceSize;
@property (
nonatomic )
UIEdgeInsets sectionInset;
@property (
nonatomic )
BOOL sectionHeadersPinToVisibleBounds
NS_AVAILABLE_IOS (
9 _0);
@property (
nonatomic )
BOOL sectionFootersPinToVisibleBounds
NS_AVAILABLE_IOS (
9 _0);
@end
上面对FlowLayout
的属性设置,当然代理方法中也有一一对应,UICollectionViewDelegateFlowLayout
常用方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@protocol UICollectionViewDelegateFlowLayout <UICollectionViewDelegate >
@optional
下面的代理方法是针对indexPath对应的item进行个性化设置
如果使用的是UICollectionViewFlowLayout布局,这些代理方法自动调用
*/
- (
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;
- (
CGFloat )collectionView:(
UICollectionView *)collectionView layout:(
UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(
NSInteger )section;
- (
CGSize )collectionView:(
UICollectionView *)collectionView layout:(
UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(
NSInteger )section;
- (
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
是每个视图决定性的布局的属性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
NS_CLASS_AVAILABLE_IOS (
6 _0)
@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;
UICollectionView与UITableView比较
不同点:
与UITableView
的最大不同,布局交给了指定的UICollectionViewLayout
布局对象。
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个方法(重写它方法,扩展功能)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- (
void )prepareLayout;
- (
nullable
NSArray <__kindof
UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(
CGRect )rect;
- (
BOOL )shouldInvalidateLayoutForBoundsChange:(
CGRect )newBounds;
- (
CGPoint )targetContentOffsetForProposedContentOffset:(
CGPoint )proposedContentOffset withScrollingVelocity:(
CGPoint )velocity;
- (
CGSize )collectionViewContentSize;
UICollectionView基本使用
初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
- (
UICollectionView *)collectionView {
if (_collectionView ==
nil ) {
UICollectionViewFlowLayout *layout = [[
UICollectionViewFlowLayout alloc] init];
layout.sectionInset =
UIEdgeInsetsMake (
20 ,
20 ,
20 ,
20 );
layout.minimumInteritemSpacing =
10 ;
layout.minimumLineSpacing =
10 ;
layout.headerReferenceSize =
CGSizeMake (
50 ,
50 );
layout.footerReferenceSize =
CGSizeMake (
50 ,
50 );
_collectionView = [[
UICollectionView alloc] initWithFrame:
self .view.bounds collectionViewLayout:layout];
_collectionView.backgroundColor = [
UIColor whiteColor];
_collectionView.dataSource =
self ;
_collectionView.delegate =
self ;
}
return _collectionView;
}
注册UICollectionView
使用的cell
类型
1
2
3
4
5
6
7
8
[
self .collectionView registerClass:[LNNumberCollectionViewCell
class ] forCellWithReuseIdentifier:cellID];
[_collectionView registerClass:[
UICollectionReusableView
class ] forSupplementaryViewOfKind:
UICollectionElementKindSectionHeader withReuseIdentifier:
@"HeadViewId" ];
[_collectionView registerClass:[
UICollectionReusableView
class ] forSupplementaryViewOfKind:
UICollectionElementKindSectionFooter withReuseIdentifier:
@"footViewId" ];
实现协议UICollectionViewDataSource
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#pragma mark - UICollectionViewDataSource
- (
NSInteger )numberOfSectionsInCollectionView:(
UICollectionView *)collectionView {
return
3 ;
}
- (
NSInteger )collectionView:(
UICollectionView *)collectionView numberOfItemsInSection:(
NSInteger )section {
return
20 ;
}
- (__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 ]];
return cell;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (
void )collectionView:(
UICollectionView *)collectionView didSelectItemAtIndexPath:(
NSIndexPath *)indexPath
{
NSLog (
@"(第%ld-区,第%ld-item)" ,indexPath.section,indexPath.item);
[collectionView cellForItemAtIndexPath:indexPath].backgroundColor = [
UIColor redColor];
}
- (
BOOL ) collectionView:(
UICollectionView *)collectionView shouldSelectItemAtIndexPath:(
nonnull
NSIndexPath *)indexPath
{
if (indexPath.row %
2 )
{
return
YES ;
}
return
NO ;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- (
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];
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
- (
BOOL )collectionView:(
UICollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(
NSIndexPath *)indexPath
{
return
YES ;
}
- (
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:" ])
{
[_collectionView performBatchUpdates:^{
[_section0Array removeObjectAtIndex:indexPath.row];
[_collectionView deleteItemsAtIndexPaths:@[indexPath]];
} completion:
nil ];
}
else
if ([
NSStringFromSelector (action) isEqualToString:
@"paste:" ])
{
NSLog (
@"-------------执行粘贴-------------" );
}
}
布局对象UICollectionViewDelegateFlowLayout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#pragma mark - UICollectionViewDelegateFlowLayout
- (
CGSize )collectionView:(
UICollectionView *)collectionView layout:(
UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(
NSIndexPath *)indexPath
{
return
CGSizeMake (
100 ,
150 );
}
- (
UIEdgeInsets )collectionView:(
UICollectionView *)collectionView layout:(
UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(
NSInteger )section;
- (
CGFloat )collectionView:(
UICollectionView *)collectionView layout:(
UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(
NSInteger )section;
- (
CGFloat )collectionView:(
UICollectionView *)collectionView layout:(
UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(
NSInteger )section;
- (
CGSize )collectionView:(
UICollectionView *)collectionView layout:(
UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(
NSInteger )section;
- (
CGSize )collectionView:(
UICollectionView *)collectionView layout:(
UICollectionViewLayout *)collectionViewLayout referenceSizeForFooterInSection:(
NSInteger )section;
自定义FlowLayout:水平滚动相册
核心代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
- (
nullable
NSArray <__kindof
UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(
CGRect )rect {
NSArray *attrs = [
super layoutAttributesForElementsInRect:
self .collectionView.bounds];
for (
UICollectionViewLayoutAttributes *attr
in attrs) {
CGFloat delta = fabs((attr.center.x -
self .collectionView.contentOffset.x) -
self .collectionView.bounds.size.width *
0.5 );
CGFloat scale =
1 - delta / (
self .collectionView.bounds.size.width *
0.5 ) *
0.25 ;
attr.transform =
CGAffineTransformMakeScale (scale, scale);
}
return attrs;
}
- (
CGPoint )targetContentOffsetForProposedContentOffset:(
CGPoint )proposedContentOffset withScrollingVelocity:(
CGPoint )velocity {
CGPoint targetP = [
super targetContentOffsetForProposedContentOffset:proposedContentOffset withScrollingVelocity:velocity];
CGFloat collectionW =
self .collectionView.bounds.size.width;
CGRect targetRect =
CGRectMake (targetP.x,
0 , collectionW, MAXFLOAT);
NSArray *attrs = [
super layoutAttributesForElementsInRect:targetRect];
CGFloat minDelta = MAXFLOAT;
for (
UICollectionViewLayoutAttributes *attr
in attrs) {
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 ;
}
return targetP;
}
附图:
期待
如果在阅读过程中遇到 error || new ideas,希望你能 messages 我,我会及时改正谢谢。
点击右上角的 喜欢 和 订阅Rss 按钮,可以收藏本仓库,并在 Demo 更新时收到邮件通知。