在iOS中,要实现九宫格数据展示,最常用的做法就是使用UICollectionView
UICollectionView继承自UIScrollView,因此支持垂直滚动或水平滚动,而且性能极佳![]()
![]()
![]()
![]()
UICollectionView在iOS6中推出得,也是UIKit视图类中的一颗新星。它和UITableView共享API设计,但也在UITableView上做了一些扩展。UICollectionView最强大、同时显著超出UITableView的特色就是其完全灵活的布局结构
UITableView和UICollectionView都是由dataSoure和delegate驱动的。他们为其显示的子视图集扮演为愚蠢的容器,对他们真实的内容毫不知情。
**UICollectionViewFlowLayout简介
UICollectionView进一步抽象了。它将其子视图的位置,大小和外观的控制权委托给一个单独的布局对象。通过提供一个自定义布局对象,你几乎可以实现任何你能想象到的布局。布局继承自UICollectionViewLayout这个抽象基类。iOS6中以UICollectionViewFlowLayout类的形式提出了一个具体的布局实现。
flow layout可以被用来实现一个标准的grid view,这可能是在collection view中最常见的使用案例了。尽管大多数人都这么想,但是Apple很聪明,没有明确的命名这个类为UICollectionViewGridLayout。而使用了更为通用的术语flow layout,这更好的描述了该类的能力:它通过一个接一个的放置cell来建立自己的布局,当需要的时候,插入横排或竖排的分栏符。通过自定义滚动方向,大小和cell之间的间距,flow
layout也可以在单行或单列中布局cell。
**如何展示数据
UICollectionView需要layout和数据源(dataSource) 来显示数据,
UICollecitonView会向数据源查询一共有多少行数据以及每一个显示什么数据等,在查询每一个显示什么数据前要确定设置了layout而且itemSize不能小于{0,0}
没有设置layout布局对象程序会崩溃
没有设置数据源和布局对象的UICollectionView只是个空壳
凡是遵守UITableViewDataSource协议的OC对象,都可以是UICollectionView的数据源
**UICollectionView常用数据源方法
调用数据源的下面方法得知一共有多少组数据
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView;
调用数据源的下面方法得知每一组有多少项数据
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section;
调用数据源的下面方法得知每一项显示什么内容
- (UICollectionViewCell *)collectionView:(UICollectionView *) collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;
UICollectionView的数据源必须实现第二个方法和第三个方法,第一个方法不实现默认就是1组
**UICollectionView的常见属性
布局对象
@property (nonatomic, strong) UICollectionViewLayout *collectionViewLayout;
背景视图,会自动填充整个UICollectionView
@property (nonatomic, strong) UIView *backgroundView;
是否允许选中cell 默认允许选中
@property (nonatomic) BOOL allowsSelection;
是否可以多选 默认只是单选
@property (nonatomic) BOOL allowsMultipleSelection;
水平进度条:shows。。。
**UICollectionViewFlowLayout常用属性
cell之间的最小行间距
@property (nonatomic) CGFloat minimumLineSpacing
cell之间的最小列间距
@property (nonatomic) CGFloat minimumInteritemSpacing;默认值为10;
cell的尺寸
@property (nonatomic) CGSize itemSize;
cell的预估尺寸
@property (nonatomic) CGSize estimatedItemSize;
UICollectionView的滚动方向,默认是垂直滚动
@property (nonatomic) UICollectionViewScrollDirection scrollDirection;
HeaderView的尺寸
@property (nonatomic) CGSize headerReferenceSize;
FooterView的尺寸
@property (nonatomic) CGSize footerReferenceSize;
分区的四边距
@property (nonatomic) UIEdgeInsets sectionInset;
设置是否当元素超出屏幕之后固定页眉视图位置,默认NO
@property (nonatomic) BOOL sectionHeadersPinToVisibleBounds;
设置是否当元素超出屏幕之后固定页脚视图位置,默认NO
@property (nonatomic) BOOL sectionFootersPinToVisibleBounds
****自定义布局的常用方法
UICollectionView将要显示时准备布局,每当布局更新时,调用该方法做布局前的准备 - (void)prepareLayout;
创建指定索引的cell的布局属性
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPat;
返回UICollectionView内所有的控件的布局属性
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect;
自定义布局时一定要实现此方法来返回UICollectionView的contentSize,内容尺寸,UICollectionView的滚动范围
- (CGSize)collectionViewContentSize;
纯代码方式使用CollectionView
#import
"ViewController.h"
@interface ViewController () <UICollectionViewDataSource>
@end
@implementation ViewController
static NSString * const ID = @"test_cell";
#pragma mark - collection view data source
// 设置组的个数
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 7;
}
// 设置每组有多少个项(格子)
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return section + 1;
}
// 返回每组的每行的cell
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
// 1. 创建Cell
// 创建一个Cell
// dequeueReusableCellWithReuseIdentifier: 方法, 首先从缓存池中查找是否有对应的cell, 如果有, 那么就返回;如果没有那么这个方法内部会帮我们创建一个cell。前提是我们需要告诉collectionview,我们要的cell的类型【将来要创建哪个类型的对象作为我们的cell】
// 注册Cell: 前提是我们需要告诉collectionview,我们要的cell的类型【将来要创建哪个类型的对象作为我们的cell】
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ID forIndexPath:indexPath];
cell.backgroundColor = [UIColor redColor];
// 2. 返回Cell
return cell;
}
#pragma mark - viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
// 1. 创建一个UICollectionView控件
// 1.1 先创建一个布局对象
@interface ViewController () <UICollectionViewDataSource>
@end
@implementation ViewController
static NSString * const ID = @"test_cell";
#pragma mark - collection view data source
// 设置组的个数
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 7;
}
// 设置每组有多少个项(格子)
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return section + 1;
}
// 返回每组的每行的cell
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
// 1. 创建Cell
// 创建一个Cell
// dequeueReusableCellWithReuseIdentifier: 方法, 首先从缓存池中查找是否有对应的cell, 如果有, 那么就返回;如果没有那么这个方法内部会帮我们创建一个cell。前提是我们需要告诉collectionview,我们要的cell的类型【将来要创建哪个类型的对象作为我们的cell】
// 注册Cell: 前提是我们需要告诉collectionview,我们要的cell的类型【将来要创建哪个类型的对象作为我们的cell】
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ID forIndexPath:indexPath];
cell.backgroundColor = [UIColor redColor];
// 2. 返回Cell
return cell;
}
#pragma mark - viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
// 1. 创建一个UICollectionView控件
// 1.1 先创建一个布局对象
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout
alloc]
init];
//也可以这样获取布局
1 .获取flowlaytout(通过拖线获取布局);,修改item的大小
// self.flowLayout.itemSize = CGSizeMake(100, 100);
2 .获取布局(通过代码获取)
UICollectionViewFlowLayout *flowLayout = (UICollectionViewFlowLayout
*)
self.collectionView.collectionViewLayout;
//
设置每个Cell的大小
flowLayout.itemSize = CGSizeMake(60, 60);
// 设置组与组之间的间隔
flowLayout.sectionInset = UIEdgeInsetsMake(50, 10, 0, 10);
// 设置每个格子之间的最小水平间距
flowLayout.minimumInteritemSpacing = 2;
// 设置行间距(设置最小行间距)
flowLayout.minimumLineSpacing = 20;
// 1.2 创建一个collection view对象
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:flowLayout];
// 设置背景色
collectionView.backgroundColor = [UIColor blueColor];
// 为collection view设置数据源对象
collectionView.dataSource = self;
flowLayout.itemSize = CGSizeMake(60, 60);
// 设置组与组之间的间隔
flowLayout.sectionInset = UIEdgeInsetsMake(50, 10, 0, 10);
// 设置每个格子之间的最小水平间距
flowLayout.minimumInteritemSpacing = 2;
// 设置行间距(设置最小行间距)
flowLayout.minimumLineSpacing = 20;
// 1.2 创建一个collection view对象
UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:flowLayout];
// 设置背景色
collectionView.backgroundColor = [UIColor blueColor];
// 为collection view设置数据源对象
collectionView.dataSource = self;
//
注册Cell:
[collectionView
registerClass:[UICollectionViewCell
class]
forCellWithReuseIdentifier:ID];
// 2. 把CollectionView添加到控制器的view中
[self.view addSubview:collectionView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
// 2. 把CollectionView添加到控制器的view中
[self.view addSubview:collectionView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//选定第一个为选中状态
NSIndexPath * indexPath = [ NSIndexPath indexPathForItem:0 inSection:0];
// 默认选中某一行的方法
NSIndexPath * indexPath = [ NSIndexPath indexPathForItem:0 inSection:0];
// 默认选中某一行的方法
[
self
selectItemAtIndexPath:indexPath
animated:YES
scrollPosition:UICollectionViewScrollPositionNone];
//
[collectionView
scrollToItemAtIndexPath:indexpath
atScrollPosition:UICollectionViewScrollPositionNone
animated:YES];
@end
注意:自定义cell时。注册cell 之后,首先需要实例化cell,必须使用initWithFrame:方法;
属性:
代理方法:
选中某行的方法
- (void)collectionView:(UICollectionView
*)collectionView didSelectItemAtIndexPath:(NSIndexPath
*)indexPath{
// 点击的时候,新闻主界面加载对应的新闻(滚动到对应的频道就会自动加载数据.)
//当选中某一行时,发出通知,
[[ NSNotificationCenter defaultCenter] postNotificationName:@"newsData" object:indexPath];
//cell本身也滚动到中心位置
[ self scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES];
// 获取模型数据
// 1. 取出这一行对应的数据
LZJNewsChannelModel * channel = self.channels[indexPath.item];
// 2. 重新赋值
// 2.1 取出这一行对应的 cell
LZJNewsChannelCell * cell =(LZJNewsChannelCell *)[collectionView cellForItemAtIndexPath:indexPath];
//重新赋值
cell.channel = channel;
// 点击的时候,新闻主界面加载对应的新闻(滚动到对应的频道就会自动加载数据.)
//当选中某一行时,发出通知,
[[ NSNotificationCenter defaultCenter] postNotificationName:@"newsData" object:indexPath];
//cell本身也滚动到中心位置
[ self scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES];
// 获取模型数据
// 1. 取出这一行对应的数据
LZJNewsChannelModel * channel = self.channels[indexPath.item];
// 2. 重新赋值
// 2.1 取出这一行对应的 cell
LZJNewsChannelCell * cell =(LZJNewsChannelCell *)[collectionView cellForItemAtIndexPath:indexPath];
//重新赋值
cell.channel = channel;
}
已经选中某行的方法:
- (void)collectionView:(UICollectionView
*)collectionView didDeselectItemAtIndexPath:(NSIndexPath
*)indexPath{
// 获取模型数据
// 1. 取出这一行对应的数据
LZJNewsChannelModel * channel = self.channels[indexPath.item];
// 2. 重新赋值
// 2.1 取出这一行对应的 cell
LZJNewsChannelCell * cell =(LZJNewsChannelCell *)[collectionView cellForItemAtIndexPath:indexPath];
//重新赋值
cell.channel = channel;
// 获取模型数据
// 1. 取出这一行对应的数据
LZJNewsChannelModel * channel = self.channels[indexPath.item];
// 2. 重新赋值
// 2.1 取出这一行对应的 cell
LZJNewsChannelCell * cell =(LZJNewsChannelCell *)[collectionView cellForItemAtIndexPath:indexPath];
//重新赋值
cell.channel = channel;
}