您的位置:首页 > 产品设计 > UI/UE

UICollectionViewController 集合视图控制器

2015-10-12 09:03 429 查看
概述:
UICollectionViewController类似于UITableViewController是UICollectionView与控制器类的整合封装.其作用也就主要体现在UICollocationView

UICollectionViewController基本属性

-(instancetype)initWithCollectionViewLayout:(UICollectionViewLayout*)
layout
@property(nonatomic,retain)UICollectionView*collectionView
@property(nonatomic,readonly)UICollectionViewLayout*collectionViewLayout
@property(nonatomic)BOOLclearsSelectionOnViewWillAppear

@property(nonatomic,assign)BOOLuseLayoutToLayoutNavigationTransitions
UICollectionView:是一种新的数据展示方式,简单来说可以把他理解成多列的UITableView.
UICollectionView概述:
标准的UICollectionView包含三个部分,他们都是UIView的子类:

Cells用于展示内容的主体,对于不同的cell可以指定不同尺寸和不同的内容,这个稍后再说
SupplementaryViews追加视图如果你对UITableView比较熟悉的话,可以理解为每个Section的Header或者Footer,用来标记每个section的view
DecorationViews装饰视图这是每个section的背景,比如iBooks中的书架就是这个----不管一个UICollectionView的布局如何变化,这三个部件都是存在的。

关于UICollectionView的实现:
实现一个UICollectionView和实现一个UITableView基本上没有什么大的区别.
他们都是同样的datasource和delegate设计模式:datasource为view提供资源,告诉view要显示些什么以及如何显示他们,delegate提供一些样式的小细节以及用户交互的响应.
同样有三个必须实现的协议方法:通过协议方法进行两个视图子类(cells/supplementaryviews)的展示.
需要注意的是,对于Decorationviews,提供方法并不在UIControllerViewDataSource中,而是直接在UICollectionViewLayout类中的(因为它仅仅于视图相关,而与数据无关).
同样具有重用机制.但是需要注意的时,在UICollectionView中,不仅cell可以重用,SupplementView和Decorationview也可以并且应该被重用的.
关于UICollectionView的代理:
UICollectionViewDelegate:View的外形,用户交互等由UICollectionViewDelegate来负责,而数据的提供则有UICollectionViewDataSource负责.
关于Cell:
相对于UITableViewCell,UICollectionViewCell则相对简单,这主要是由于展示对象的性质决定的,因为UICollectionView展示的对象更为灵活,因此需求也就千奇百怪.因此SDK提供给我们的默认UICollectionViewCell在结构上比较简单,由上至下:cell本身的View/backgroundView/selectedBackgroundView/
contentView.
UICollectionViewLayout:
UICollectionView的精髓.可以通过对其子类化实现对单元格的自定义布局,这也就是UICollectionView和UITableView的最大区别了.UICollectionViewLayout可以说时UICollectionView的大脑和中枢,它负责cellSupplementaryView和DecorationViews进行组织,为他们设定各自的属性,
包括但不限于:位置/尺寸/透明度/层级关系/形状/等等....
Apple为我们提供了一个最简答可能也是最常用的默认的layout对象,UICollectionViewFlowLayout.FlowLayout简单说就是一个直线对其的layout.通过对这个子类的子类化可以实现大部分的瀑布流类的简单实现.
总结:
总的来说,一个UICollectionView的实现必须包含两个必要的部分:UICollectionViewDataSource和UICollectionViewLayout分别提供展示的View内容和展示的View的位置.和一个交互部分:UICollectionViewDelegate.而Apple给出的UICollectionViewFlowLayout已经是一个很强力的layout方案了.但是仅仅如此还是不够的.
UICollectionView的强大之处,就在于各种layout的自定义实现,以及他们之间的切换.

1.UICollectionView
1.1基本属性/方法

@property(nonatomic,assign)id<UICollectionViewDelegate>delegate
@property(nonatomic,assign)id<UICollectionViewDataSource>dataSource
代理
@property(nonatomic,retain)UIView*backgroundView
背景视图
-(void)registerClass:(Class)
viewClass
forSupplementaryViewOfKind:(NSString*)
elementKind

withReuseIdentifier:(NSString*)
identifier

-(id)dequeueReusableCellWithReuseIdentifier:(NSString*)
identifier

forIndexPath:(NSIndexPath*)
indexPath

重用方法

@property(nonatomic,retain)UICollectionViewLayout*collectionViewLayout
-(void)setCollectionViewLayout:(UICollectionViewLayout*)layout

animated:(BOOL)
animated

切换布局
-(void)reloadData
-(void)reloadSections:(NSIndexSet*)
sections

-(void)reloadItemsAtIndexPaths:(NSArray*)
indexPaths

数据更新
-(NSInteger)numberOfSections
-(NSInteger)numberOfItemsInSection:(NSInteger)
section

-(NSArray*)visibleCells
获取内容数量
-(void)insertItemsAtIndexPaths:(NSArray*)
indexPaths

-(void)moveItemAtIndexPath:(NSIndexPath*)
indexPath

toIndexPath:(NSIndexPath*)
newIndexPath

-(void)deleteItemsAtIndexPaths:(NSArray*)
indexPaths


添加/移动/删除items(类似tableView的增删改)
-(void)insertSections:(NSIndexSet*)
sections

-(void)deleteSections:(NSIndexSet*)
sections

-(void)moveSection:(NSInteger)
section

toSection:(NSInteger)
newSection

添加/删除/移动sections
@property(nonatomic)BOOLallowsSelection
@property(nonatomic)BOOLallowsMultipleSelection
-(NSArray*)indexPathsForSelectedItems
-(void)selectItemAtIndexPath:(NSIndexPath*)
indexPath

animated:(BOOL)
animated

scrollPosition:(UICollectionViewScrollPosition)
scrollPosition

-(void)deselectItemAtIndexPath:(NSIndexPath*)indexPath

animated:(BOOL)
animated


是否可选
-(NSIndexPath*)indexPathForItemAtPoint:(CGPoint)
point

-(NSArray*)indexPathsForVisibleItems
-(NSIndexPath*)indexPathForCell:(UICollectionViewCell*)
cell

-(UICollectionViewCell*)cellForItemAtIndexPath:(NSIndexPath*)
indexPath

对item/section进行定位
-(UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath*)
indexPath

-(UICollectionViewLayoutAttributes*)layoutAttributesForSupplementaryElementOfKind:(NSString*)
kind

atIndexPath:(NSIndexPath*)
indexPath

获取布局信息
-(void)performBatchUpdates:(void
(^)(void))
updates

completion:(void
(^)(BOOLfinished))
completion

多点选择的删除于移动
1.2常用操作
添加/删除/移动/编辑

1.3UICollectionViewDataSource/UICollectionViewDelegate协议

UICollectionViewDataSource
-(BOOL)collectionView:(UICollectionView*)
collectionView

shouldSelectItemAtIndexPath:(NSIndexPath*)
indexPath

-(void)collectionView:(UICollectionView*)
collectionView

didSelectItemAtIndexPath:(NSIndexPath*)
indexPath

-(BOOL)collectionView:(UICollectionView*)
collectionView

shouldDeselectItemAtIndexPath:(NSIndexPath*)
indexPath

-(void)collectionView:(UICollectionView*)
collectionView

didDeselectItemAtIndexPath:(NSIndexPath*)
indexPath


选中状态历程
-(BOOL)collectionView:(UICollectionView*)
collectionView

shouldHighlightItemAtIndexPath:(NSIndexPath*)
indexPath

-(void)collectionView:(UICollectionView*)
collectionView

didHighlightItemAtIndexPath:(NSIndexPath*)
indexPath

-(void)collectionView:(UICollectionView*)
collectionView

didUnhighlightItemAtIndexPath:(NSIndexPath*)
indexPath

-(void)collectionView:(UICollectionView*)
collectionView
willDisplayCell:(UICollectionViewCell*)
cell

forItemAtIndexPath:(NSIndexPath*)
indexPath

-(void)collectionView:(UICollectionView*)
collectionView
willDisplaySupplementaryView:(UICollectionReusableView*)
view
forElementKind:(NSString*)
elementKind

atIndexPath:(NSIndexPath*)
indexPath

-(void)collectionView:(UICollectionView*)
collectionView
didEndDisplayingCell:(UICollectionViewCell*)
cell

forItemAtIndexPath:(NSIndexPath*)
indexPath

-(void)collectionView:(UICollectionView*)
collectionView
didEndDisplayingSupplementaryView:(UICollectionReusableView*)
view
forElementOfKind:(NSString*)
elementKind

atIndexPath:(NSIndexPath*)
indexPath

监控单元格的加载于移除
-(UICollectionViewTransitionLayout*)collectionView:(UICollectionView*)
collectionView
transitionLayoutForOldLayout:(UICollectionViewLayout*)
fromLayout

newLayout:(UICollectionViewLayout*)
toLayout

-(BOOL)collectionView:(UICollectionView*)
collectionView

shouldShowMenuForItemAtIndexPath:(NSIndexPath*)
indexPath


编辑菜单
-(BOOL)collectionView:(UICollectionView*)collectionView
canPerformAction:(SEL)
action
forItemAtIndexPath:(NSIndexPath*)
indexPath

withSender:(id)
sender


-
(void)collectionView:(UICollectionView*)
collectionView


performAction:(SEL)
action
forItemAtIndexPath:(NSIndexPath*)
indexPath

withSender:(id)
sender

当编辑菜单存在时可用

1.4实例
//1创建用于布局单元格的布局对象

UICollectionViewFlowLayout
*flowLayout1=[[UICollectionViewFlowLayoutalloc]init];

//2设置最小行间距

flowLayout1.minimumInteritemSpacing=
5;

//3设置最小列间距

flowLayout1.minimumLineSpacing=
5;

//4设置单元格的大小

flowLayout1.itemSize
=CGSizeMake((CGRectGetWidth(self.view.bounds)
-15)/2
,(CGRectGetWidth(self.view.bounds)
-15)/2);

//5设置布局时的内边距

flowLayout1.sectionInset
=UIEdgeInsetsMake(5,5,5,5);

//使用自定义的layout布局

WaterFlowLayout
*flowLayout=[[WaterFlowLayout
alloc]
init];

flowLayout.columnCount
=2;//表示有两列

flowLayout.delegate
=self;

flowLayout.sectionInset
=UIEdgeInsetsMake(10,10,10,10);

flowLayout.itemWitdth
=(CGRectGetWidth(self.view.bounds)
-30
)/2;

UICollectionView
*collectionView=[[UICollectionViewalloc]initWithFrame:self.view.boundscollectionViewLayout:flowLayout];

collectionView.tag
=1001;

//设置背景颜色

collectionView.backgroundColor=[UIColorwhiteColor];

//设置代理

collectionView.delegate
=self;

collectionView.dataSource
=self;

[self.viewaddSubview:collectionView];

[collectionViewrelease];

[flowLayoutrelease];

//为对应重用标示注册单元格类型
[collectionViewregisterClass:[ImageCollectionViewCellclass]forCellWithReuseIdentifier:@"CELL"];
//执行协议方法
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView*)collectionView
{

return
1;

}

//返回制定分区的单元格数量

-(NSInteger)collectionView:(UICollectionView*)collectionViewnumberOfItemsInSection:(NSInteger)section
{

return
self.datasource.count;

}

//返回对应行的单元格对象

-(UICollectionViewCell
*)collectionView:(UICollectionView*)collectionViewcellForItemAtIndexPath:(NSIndexPath*)indexPath
{

ImageCollectionViewCell
*cell=[collectionViewdequeueReusableCellWithReuseIdentifier:@"CELL"forIndexPath:indexPath];

cell.backgroundColor
=[UIColor
colorWithRed:arc4random()%256
/255.0
green:arc4random()%256
/255.0
blue:arc4random()%256
/255.0
alpha:1];

ImageModel
*model=self.datasource[indexPath.item];

[cell.imageView
setImageWithURL:[NSURLURLWithString:model.thumbURL]];

return
cell;

}

2.UICollectionViewLayout

集合视图控制器布局对象完成了对集合视图控制器对象单元格frame的布局,所以其核心即单元格frame的布局,最终要求即获得一个单元格属性模型数组.
2.1基本属性

@property(nonatomic,readonly)UICollectionView*collectionView
-(CGSize)collectionViewContentSize
当前使用此布局对象的集合视图
同时还提供了相应的cell布局的切换/cell的增/删/移动
2.2自定义
自定义布局时,必须要重写的方法如下:
prepareLayout(即将开始布局时调用.重写此方法,实现在即将布局时,获取属性模型数组)

collectionViewContentSize(重写此方法返回collectionView的contentSize)

layoutAttributesForElementsInRect:(重写此方法返回属性模型数组)


layoutAttributesForItemAtIndexPath:(重写此方法返回对应indexPath的属性模型)


layoutAttributesForSupplementaryViewOfKind:atIndexPath:
(ifyourlayoutsupportssupplementaryviews)

layoutAttributesForDecorationViewOfKind:atIndexPath:
(ifyourlayoutsupportsdecorationviews)

shouldInvalidateLayoutForBoundsChange:


如果对应的collection需要实现增加/删除/移动功能,则需要重写以下方法

initialLayoutAttributesForAppearingItemAtIndexPath:


initialLayoutAttributesForAppearingSupplementaryElementOfKind:atIndexPath:


initialLayoutAttributesForAppearingDecorationElementOfKind:atIndexPath:


finalLayoutAttributesForDisappearingItemAtIndexPath:


finalLayoutAttributesForDisappearingSupplementaryElementOfKind:atIndexPath:


finalLayoutAttributesForDisappearingDecorationElementOfKind:atIndexPath:


另外视图布局对象也提供了一些方法用于提升性能

UICollectionViewLayout的自定义大概可以分为一下几步:
1>根据需求扩展UICollectionView的协议方法

2>定义需求的属性信息(因为UICollectionViewLayout基类的属性)
3>获取cell的的属性模型数组(自定义的核心)
4>重写相应的父类方法(基本状态下有:)

2.4:自定义实例(瀑布流)

#import
<UIKit/UIKit.h>

@class
WaterFlowLayout;

//声明扩展协议

@protocol
WaterFlowLayoutDelegate<UICollectionViewDelegate>

//为布局对象返回单元格的最终高度

-(CGFloat)collectionView:(UICollectionView*)collectionViewlayout:(WaterFlowLayout*)waterFlowLayout
heightyForItemAtIndexPath:(NSIndexPath*)indexPath;

@end

@interface
WaterFlowLayout:UICollectionViewLayout

@property
(nonatomic,assign)id<WaterFlowLayoutDelegate>delegate;//代理对象属性

@property
(nonatomic,assign)NSUInteger
columnCount;//设置瀑布流的列数

@property
(nonatomic,assign)CGFloat
itemWitdth;
//设置瀑布流中每个单元格的宽度

@property
(nonatomic,assign)UIEdgeInsets
sectionInset;//设置瀑布流的内边距

@end
#import"WaterFlowLayout.h"

@interfaceWaterFlowLayout
()

@property(nonatomic,assign)NSUInteger
numberOfItems;//总的单元格数量

@property
(nonatomic,assign)CGFloat
interItemSpacing;//列间距

@property
(nonatomic,retain)NSMutableArray
*columnHeights;//保存布局时当前每一列的当前总高度.有多少列,就有多少个数组元素

@property
(nonatomic,retain)NSMutableArray
*itemAttributes;//用于保存每一个单元格的属性模型对象.
-(NSInteger)shortestColumnIndex;//返回columnHeights数组中当前最短列下标
-(NSInteger)longestColumnIndex;//返回columnHeightss数组中当前最长列下标

@end

@implementationWaterFlowLayout

-(void)dealloc

{

[_columnHeights
release];

[_itemAttributes
release];

[super
dealloc];

}

-(NSMutableArray
*)columnHeights

{

if
(!_columnHeights){

self.columnHeights=[NSMutableArrayarray];

}

return
_columnHeights;

}

-(NSMutableArray
*)itemAttributes

{

if
(!_itemAttributes){

self.itemAttributes=[NSMutableArrayarray];

}

return
_itemAttributes;

}

-(NSInteger)shortestColumnIndex

{

NSInteger
index=0;

CGFloat
shortestHeight=CGFLOAT_MAX;//浮点数的最大值

for
(int
i=0
;i<self.columnHeights.count;i++)
{

CGFloat
currentHeight=[self.columnHeights[i]doubleValue];

if
(currentHeight<shortestHeight){

index=i;

shortestHeight=currentHeight;

}

}

return
index;

}

-(NSInteger)longestColumnIndex

{

NSInteger
indext=0;

CGFloat
longestHeight=0;

for
(int
i=0;i<self.columnHeights.count;
i++){

CGFloat
currentHeight=[self.columnHeights[i]doubleValue];

if
(currentHeight>longestHeight){

indext=i;

longestHeight=currentHeight;

}

}

return
indext;

}

-(void)layoutItems

{

//获取单元格的总数量

self.numberOfItems=[self.collectionViewnumberOfItemsInSection:0];

//计算内容区域的最终宽度

CGFloat
contentWidth=CGRectGetWidth(self.collectionView.bounds)
-self.sectionInset.left-
self.sectionInset.right;

//计算列边距

self.interItemSpacing=(contentWidth-
self.columnCount*
self.itemWitdth)/(self.columnCount-
1);

//先通过列数为columnHeight添加当前高度

for
(int
i=0
;i<self.columnCount;i++){

//语法糖自动转数据为对象类型

self.columnHeights[i]=@(self.sectionInset.top);

}

for
(int
i=0
;i<self.numberOfItems;i++){

//创建单元格对应的indexPath对象

NSIndexPath
*indexPath=[NSIndexPath
indexPathForItem:i
inSection:0];

//通过代理对象得到单元格的最终高度

CGFloat
itemHeight=[self.delegatecollectionView:self.collectionViewlayout:selfheightyForItemAtIndexPath:indexPath];

//获取当前最小列的下标

NSInteger
shortestIndex=[self
shortestColumnIndex];

//计算单元格的x,y轴坐标

CGFloat
x=self.sectionInset.left+
(self.itemWitdth+self.interItemSpacing)
*shortestIndex;

CGFloat
y=[self.columnHeights[shortestIndex]doubleValue]
;

//创建属性模型对象

UICollectionViewLayoutAttributes*attributes=[UICollectionViewLayoutAttributeslayoutAttributesForCellWithIndexPath:indexPath];

//设置frame

attributes.frame
=CGRectMake(x,y,self.itemWitdth,
itemHeight);

//保存在属性数组中

[self.itemAttributesaddObject:attributes];

//更新当前列(最短列)的总高度

self.columnHeights[shortestIndex]=@(y
+itemHeight+self.interItemSpacing);

NSLog(@"%@",NSStringFromCGRect(attributes.frame));

}

}

-(void)prepareLayout

{

[super
prepareLayout];

//在准备布局时调用此方法计算每个单元格的frame

[self
layoutItems];

}

-(NSArray
*)layoutAttributesForElementsInRect:(CGRect)rect

{

//为当前区域返回对应保存属性模型的数组

return
self.itemAttributes;

}

-(UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath*)indexPath

{

//为每个单元格分发对应的属性模型的对象

return
self.itemAttributes[indexPath.item];

}

-(CGSize)collectionViewContentSize

{

CGSize
contentSize=self.collectionView.frame.size;

//获取最长列的下标

NSInteger
longestIndex=[self
longestColumnIndex];

contentSize.height
=[self.columnHeights[longestIndex]doubleValue];

return
contentSize;

}

@end
2.3UICollectionViewFlowLayout
提供了一个简单的集合视图布局,能够实现自定义行数的简单布局.通过itemSize/行间距/列间距/内边距实现单的布局
3.UICollectionViewCell
只具有四个五个属性提供了自定义空间(contentView/backgroundView/selectedBackgroundView)
和选择状态(selected/highlighted)

4.UICollectionViewLayoutAttributes
用于保存属性的模型类,适用于UICollectionViewLayout的初始化方法为+(id)layoutAttributesForCellWithIndexPath:(NSIndexPath*)indexPath
可以保存的属性主要有:frame/bounds/center/size/transform3D/transform/alpha/zIndex(堆叠顺序)/hidden
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: