UICollectionView基础学习
iOS6引入的集合(CollectionView)是一种网格状视图, 用来排布其中的各个单元格, 他们不仅仅是能够垂直滚动的一列单元格. 集合视图的许多概念与表格相同, 当却更强大, 也更加灵活
本次将介绍集合视图的一些基本知识, 包括他的数据源, 特殊用途, 以及单元格等. 同学们将会学到如何开发标准的集合视图与自定义的集合视图, 如何在视图中添加特效, 以及如是使用内置的动画功能来创建相当高效的交互方式
1.1 集合视图与表视图的异同
UICollectionView 实例会把各项数据展示成一份有序集合. 与表视图一样, 集合视图也有单元格, 头部及尾部构成, 而且由数据源及委托驱动, 但与表格不同的地方在于, 集合视图还引入了与布局有关的类, 这个类用来指定各个条目应该如何摆放在屏幕上, 该类负责管理各个单元格的位置, 使得对应的条目可以在必要时出现在适当的位置
对比项 | 集合视图 | 表格 |
---|---|---|
主类 | UICollectionView | UITableView |
控制器 | UICollectionViewController | UITableViewController |
内容 | 单元格,补充视图(头部或者尾部), 装饰视图(背景图版及视觉装饰) | 单元格, 头部, 尾部 |
由用户所触发的重新载入 | reloadData | reloadData |
可复用单元格 | UICollectionViewCell(通过 dequeueReuseableCellWithReuseIdentifier:forIndexPath: 获取) | UITableViewCell(通过 dequeueReuseableCellWithReuseIdentifier:forIndexPath: 获取) |
注册 | 类或 XIB 来注册可复用单元格, 补充视图以及装饰图 | 用类或 XIB 来注册可复用单元格 |
头部及尾部 | UICollectionReusableView | UITableViewHeaderView, UITableViewFooterView |
布局 | UICollectionViewLayout 及 UICollectionViewFlowLayout | 不适用 |
数据源 | UICollectionDataSource | UITableViewDataSource |
委托 | UICollectionViewDelegate | UITableViewDelegate |
用于布局的委托 | UICollectionViewDelegateFlowlayout | 不适用 |
索引机制 | 通过区段与条目索引 | 通过区段与行来定位 |
滚动方向 | 水平或垂直 | 垂直 |
视觉效果 | 自定义设置 | 不适用 |
1.2 两者在实现层的区别
编写程序时, 构建表格视图和构建集合视图所用的代码是有几个地方不同的. 集合视图不允许相互局的延迟加载. 在创建集合视图时, 为该视图提供内容的数据源必须按时完全准备好的. 我们不能等到程序执行初始化方法, loadView 方法或者 viewDidLoad 方法的时候在准备数据源, 而是必须把他准备好.
可以再应用程序委托中准备, 也可以在实例化集合视图并将它添加到其他试图之前, 或者把集合视图控制器设置为其他控制器的子控制器之前
展示集合视图之前, 一点要把集合视图的布局对象完全准备好
MyCollectionViewController *mcc = [[MyCollectionViewController alloc] initWithCollectionViewLayout:layout];
集合视图的生命周期中并不只能有一种布局, 可以使用 collectionViewLayout 属性来访问集合视图的布局, 修改这个属性之后, 视图就会以不带动画方式立即更新其布局, iOS7 提供了一个简单带动画的布局切换方式
- (void)setCollectionViewLayout:animated:completion:
- 建立集合视图
2.1 通过控制器使用集合视图
构建控制器时, 首先创建并设置号其布局对象, 然后分配新的实例, 并用准备好的布局对象初始化
UICollectionViewFlowLayout *layout = [[UICollectionFlowLayout alloc] init];
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; // 修改滚动方向
MyCollectionViewController *mcc = [[MyCollectionViewController alloc] initWithCollectionViewLayout:layout];
2.2 直接使用集合视图
UICollectionViewFlowLayout *layout = [[UICollectionFlowLayout alloc] init];
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; // 修改滚动方向
collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
collectionView.dataSource = self;
collectionView.delegate = self;
2.3 数据源与委托
管理集合视图的视图控制器会宣称自己实现了 UICollectionViewDataSource, UICollectionViewDelegate 协议, 如果使用 FlowLayout 布局控制器还会宣称实现了 UICollectionViewDelegateFlowLayout 协议, 该协议通过一系列回调方法来个集合视图的布局对象提供布局信息
与表视图一样, 数据源提供了每个区段以及区段内每个条目的信息, 并根据需求返回对应的单元格以及集合视图上面的其他部件, 委托处理用户操作, 并对用户的改动请求作出回应, UICollectionViewDelegateFlowLayout 则负责提供该区段的详细的布局信息, 大多数情况下, 它的方法都是可选的
- 流式布局
3.1 滚动方向: scrollDirection 属性决定了视图中的区段是水平排列还是垂直排列, 水平滚动: 元素布局时会优先将垂直方向的空间填充完毕,然后开启下一列; 垂直滚动则优先将水平空间填充完毕,然后开启下一行
3.2 条目尺寸,行间距: minimumLineSpacing, minimumInteritemSpacing 属性规定了每个区段内条目之间的距离; 行间距( line spacing)表示连个相邻行之间的距离, 在水平布局下是垂直方向, 在垂直布局下时水平方向
3.3 头部与尾部尺寸: headerReferenceSize, footerReferenceSize 属性定义了区段的头部和尾部应该有多宽, 多高, 接收的值为 CGSize, 当为水平布局时使用宽度字段, 垂直布局时, 使用高度字段
以上2,3属性均可以在 UICollectionViewDelegateFlowLayout 中设置
collectionView:layout:sizeForItemAtIndexPath --- 方法与 itemSize 属性相对应, 他可以指定具体每个条目尺寸
collectionView:layout:minimumLineSpacingForSectionAtInde: --- 方法与 minimumLineSpacing 属性对应, 他可以具体到每个区段内的最小行间距
collectionView:layout:minimumInteritemSpacingForSectionAtInde: --- 方法与 minimumInteritemSpacing 属性相对应, 他可以具体控制每个区段内的最小条目间距
collectionView:layout:referenceSizeForHeaderInSection: --- 与 headerReferenceSize 相对应
collectionView:layout:referenceSizeForHeaderInSection: --- 与 footerReferenceSize 相对应
3.4 内边距: 最小行距及最小条目间距属性定义了区段内的某个条目与其他条目之间的位置关系, 与之对应 sectionInset 属性则描述了区段内所有条目的总体边界与外围的集合视图的边界
上代码: 1.
采用流式布局的简单集合视图
1. 在 storyBoard 中创建一个 UICollectionViewController
2.
#import <UIKit/UIKit.h>
@interface ViewController : UICollectionViewController
@end
#import "ViewController.h"
@interface ViewController ()<UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>
@property (nonatomic, assign) BOOL useHeader;
@property (nonatomic, assign) BOOL useFooter;
@property (nonatomic, assign) NSInteger numberOfSectin;
@property (nonatomic, assign) NSInteger itemsInSection;
@end
@implementation ViewController
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout
{
if (self = [super initWithCollectionViewLayout:layout]) {
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.useFooter = NO;
self.useHeader = NO;
self.numberOfSectin = 1;
self.itemsInSection = 10;
// 注册 Cell
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cell"];
// 注册 Header
[self.collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"header"];
// 注册 Footer
[self.collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"footer"];
self.collectionView.backgroundColor = [UIColor lightGrayColor];
// 允许用户多选
self.collectionView.allowsMultipleSelection = YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - UICollectionViewDataSource
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return self.numberOfSectin;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.itemsInSection;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
cell.backgroundColor = [UIColor whiteColor];
cell.selectedBackgroundView = [[UIView alloc] initWithFrame:CGRectZero];
cell.selectedBackgroundView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5f];
return cell;
}
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
if (kind == UICollectionElementKindSectionHeader) {
UICollectionReusableView *header = [self.collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"header" forIndexPath:indexPath];
header.backgroundColor = [UIColor blackColor];
return header;
} else if (kind == UICollectionElementKindSectionFooter) {
UICollectionReusableView *footer = [self.collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"footer" forIndexPath:indexPath];
footer.backgroundColor = [UIColor darkGrayColor];
return footer;
}
return nil;
}
#pragma mark - UICollectionViewDelegate
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"Selected item at indexPath: %@", indexPath);
}
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(@"Deselect item at indexPath: %@",indexPath);
}
#pragma mark - UICollectionViewDelegateFlowLayout
// header 大小
- (CGSize) collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
{
return self.useHeader ? CGSizeMake(60.0, 30.0) : CGSizeZero;
}
/// footer 大小
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section
{
return self.useFooter ? CGSizeMake(60.0, 30.0) : CGSizeZero;
}
@end
<img src="http:https://img.haomeiwen.com/i536129/62df25095adb23b9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "320" height = "480" alt="图片名称" align=center />
网友评论