IOS集合视图UICollectionView之王朝Demo
从本回开始,我们介绍集合视图的使用,以及对应的数据源和协议的使用,在本次Demo中将网页和表格视图一起回顾--本次的案例与之前的案例分析中都有使用网页的载入「直接载入网页,会使得线程阻塞,我们会在下一回文章中重点分析多线程的相关概念,并完善多线程处理网页的问题」
一.表格视图
-
我们需要先来看一个典型的集合视图的案例
图1--IBook界面
我们通过IBook来认识一下集合视图,在表格视图中我们可以看到这几个元素:单元格,节,补充视图和装饰视图--其中这里在本图片中最突出的是单元格,和节
- 单元格
IBook中每一本书都可以看做一个单元格,每个单元格中都含有一个imageView
- 节
节充分的体现集合视图的行数
二.表格视图的数据源协议和委托协议
- collectionView:numberOfItemInSection
提供每个节中的列数
- numberOfSectionInCollectionView
提供节的个数「行数」
- collectionView:cellForItemAtIndexPath
为某个单元格提供显示数据
- collectionView:viewForSupplementaryElementOfKind:atIndexPath
为补充视图提供数据
- collectionView:didSelectItemAtIndexPath
选择单元格之后触发
- collectionView:didDeselectItemAtIndexPath
取消选择单元格之后触发
案例「王朝」
效果图
图2--运行效果图
项目图
代码实现
分析:观察效果图,我们不难发现,总共有九个单元格,其中每一个节含有三个列,总共有三个节,同时每一个单元格都是有相应的图片设置,以及每个单元格下方都有标签的标志
首先,我们要创建一个通用的集合视图--创建一个新的viewController文件,在头文件中,我们定义一个公共的API,根据分析,每一个单元格就是一个UI视图,其中包含了UIImageView和UILabel两部分组成
@interface EventCollectionViewCell : UICollectionViewCell
@property (nonatomic,strong) UIImageView *imageView; //单元格图需要图片视图
@property (nonatomic,strong) UILabel *label; //还有标签
@end
接下来,我们需要初始化单元格中的图片视图,刚才提及每一个单元格视图都是一个单独的视图,但是它们不是UIView,因此没有ViewDidVIew()方法进行初始化,因此,我们采用initWithFrame进行初始化单元格视图
//因为集合视图没有viewDidView();
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
//创建一个单元格
CGFloat cellWidth = self.frame.size.width;
CGFloat imageViewWidth = 101;
CGFloat imageViewHeight = 101;
CGFloat imageViewTopView = 15;
//1.创建imageView
self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake((cellWidth-imageViewWidth)/2, imageViewTopView, imageViewWidth, imageViewHeight)];
[self addSubview:self.imageView];
//2.创建一个标签
CGFloat labelWidth = 101;
CGFloat labelHeight = 16;
CGFloat labelViewTopView = 120;
self.label = [[UILabel alloc] initWithFrame:CGRectMake((cellWidth-labelWidth)/2, labelViewTopView, labelWidth, labelHeight)];
self.label.textAlignment = NSTextAlignmentCenter;
self.label.font = [UIFont systemFontOfSize:13];
self.label.textColor = [UIColor whiteColor];
[self addSubview:self.label];
}
return self;
}
分析:通过父类的构造方法来创建自己的构造方法,并返回,在构造方法当中,我们初始化了单元格以及标签,我们通过self.frame.size.width设置宽度是整个屏幕的宽度
通用的类封装后,我们需要导入自己制作好的属性列表plist文件 图3--属性列表文件
此处我们通过数组来存储plist文件的信息,并设置集合视图
@interface ViewController () <UICollectionViewDelegate,UICollectionViewDataSource,WKNavigationDelegate>
@property (nonatomic,strong) NSArray *events; //存储plist信息
@property (nonatomic,strong) UICollectionView *collectionView; //集合视图
@property (nonatomic,strong) WKWebView *webView;
@end
- (void)viewDidLoad {
[super viewDidLoad];
//获取plist属性文件的内容
NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"events" ofType:@"plist"];
self.events = [[NSArray alloc] initWithContentsOfFile:plistPath];
[self setupCollectionView]; //建立集合视图
}
- (void)setupCollectionView{
//创建流式布局
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
//设置每个格子的大小
layout.itemSize = CGSizeMake(80, 80);
//设置整个collectionView的内边距
layout.sectionInset = UIEdgeInsetsMake(15, 15, 30, 15);
layout.headerReferenceSize = CGSizeMake(15, 15);
layout.footerReferenceSize = CGSizeMake(10, 10);
//当手机屏幕大于560时候则,重新绘制内边距sectionInset和每个格子的大小itemSize
CGSize screenSize = [UIScreen mainScreen].bounds.size;
if (screenSize.height > 568) {
layout.itemSize = CGSizeMake(100, 100);
layout.sectionInset = UIEdgeInsetsMake(15, 15, 20, 15);
layout.headerReferenceSize = CGSizeMake(80, 80);
layout.footerReferenceSize = CGSizeMake(20, 20);
}
//设置单元格之间的间距
layout.minimumLineSpacing = 5;
self.collectionView = [[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:layout];
[self.collectionView registerClass:[EventCollectionViewCell class] forCellWithReuseIdentifier:@"cellIdentifier"];
//设置屏幕背景
UIImageView *imageBackgroundView=[[UIImageView alloc] initWithFrame:UIScreen.mainScreen.bounds];
imageBackgroundView.image=[UIImage imageNamed:@"backImage"];
self.collectionView.backgroundView = imageBackgroundView;
self.collectionView.delegate = self; //协议
self.collectionView.dataSource = self; //数据源
[self.view addSubview:self.collectionView];
}
分析:我们通过创建集合视图中的流式布局进行初始化,定义了每个单元格的大小,以及上下宽度的大小,同时对于大屏设备提供了不同数值参数的转换,最后将设置好的流式布局添加到集合视图中。
最后,实现数据源协议和委托协议
#pragma mark -- 实现数据源
#define COL_NUM 3
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
//设置单元格的个数
int num = [self.events count] % COL_NUM;
if(num == 0){
//奇数
return [self.events count] / COL_NUM;
}else{
//偶数
return [self.events count] / COL_NUM + 1;
}
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
//section --> 节
return COL_NUM;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
EventCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cellIdentifier" forIndexPath:indexPath];
//计算events集合的下标索引
NSInteger idx = indexPath.section * COL_NUM + indexPath.row;
if (self.events.count <= idx) {
return cell;
}
//利用字典存储属性列表
NSDictionary *event = self.events[idx];
cell.label.text = event[@"name"];
cell.imageView.image = [UIImage imageNamed:event[@"image"]];
return cell;
}
#pragma mark -- 协议
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
NSDictionary *event = self.events[indexPath.section * COL_NUM + indexPath.row];
NSLog(@"select the collectionView is %@",event);
[self setWebViewSetting:[event objectForKey:@"name"]];
}
- (void)setWebViewSetting:(NSString *)name{
self.webView = [[WKWebView alloc] initWithFrame:CGRectMake((UIScreen.mainScreen.bounds.origin.x), (UIScreen.mainScreen.bounds.origin.y+20), UIScreen.mainScreen.bounds.size.width, UIScreen.mainScreen.bounds.size.height)];
[self setURL:name];
[self closeTheWebView];
self.webView.navigationDelegate = self;
[self.collectionView addSubview:self.webView];
}
- (void)closeTheWebView{
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = CGRectMake(0, UIScreen.mainScreen.bounds.origin.y+5, 50, 5);
[button setTitle:@"Back" forState:UIControlStateNormal];
[button addTarget:self
action:@selector(closeTheWebViewButton:) forControlEvents:(UIControlEventTouchUpInside)];
[self.webView addSubview:button];
}
- (void)closeTheWebViewButton:(id)sender{
[self.webView removeFromSuperview];
}
- (void)setURL:(NSString *)name{
if ([name isEqualToString:@"秦朝"]) {
NSString *urlPath = @"http://www.qulishi.com/qinchao/";
NSURL *url = [NSURL URLWithString:urlPath];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}else if([name isEqualToString:@"汉朝"]){
NSString *urlPath = @"http://www.qulishi.com/hanchao/";
NSURL *url = [NSURL URLWithString:urlPath];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}else if([name isEqualToString:@"隋朝"]){
NSString *urlPath = @"http://www.qulishi.com/suichao/";
NSURL *url = [NSURL URLWithString:urlPath];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}else if([name isEqualToString:@"唐朝"]){
NSString *urlPath = @"http://www.qulishi.com/tangchao/";
NSURL *url = [NSURL URLWithString:urlPath];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}else if([name isEqualToString:@"元朝"]){
NSString *urlPath = @"http://www.qulishi.com/yuanchao/";
NSURL *url = [NSURL URLWithString:urlPath];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}else if([name isEqualToString:@"明朝"]){
NSString *urlPath = @"http://www.qulishi.com/mingchao/";
NSURL *url = [NSURL URLWithString:urlPath];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}else if([name isEqualToString:@"清朝"]){
NSString *urlPath = @"http://www.qulishi.com/qingchao/";
NSURL *url = [NSURL URLWithString:urlPath];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}else if([name isEqualToString:@"民国"]){
NSString *urlPath = @"http://www.qulishi.com/minguo/";
NSURL *url = [NSURL URLWithString:urlPath];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}else if([name isEqualToString:@"中华人民共和国"]){
NSString *urlPath = @"http://www.gov.cn";
NSURL *url = [NSURL URLWithString:urlPath];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}
}
- (void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
}
#pragma mark -- 网页协议
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
NSLog(@"start.....");
[self.webView configuration];
[self.webView allowsBackForwardNavigationGestures];
[self.webView backForwardList];
}
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{
NSLog(@"commit.....");
}
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
NSLog(@"finished.....");
}
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error{
NSLog(@"error.....");
if (error) {
[self.collectionView willRemoveSubview:self.webView];
}
}
分析:不关注网页设置部分,我们来看集合视图的协议部分
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
//设置集合视图节的个数
int num = [self.events count] % COL_NUM;
if(num == 0){
//奇数
return [self.events count] / COL_NUM;
}else{
//偶数
return [self.events count] / COL_NUM + 1;
}
}
此处,我们设置了集合视图节的个数,当与3进行取模运算时候,如果整除则为奇数,否则为偶数
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
//section --> 节
return COL_NUM;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
EventCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cellIdentifier" forIndexPath:indexPath];
//计算events集合的下标索引
NSInteger idx = indexPath.section * COL_NUM + indexPath.row;
if (self.events.count <= idx) {
return cell;
}
//利用字典存储属性列表
NSDictionary *event = self.events[idx];
cell.label.text = event[@"name"];
cell.imageView.image = [UIImage imageNamed:event[@"image"]];
return cell;
}
图4--点击单元格运行结果
通过,返回COL_NUM设置一个节中含有单元格的数目,并且,通过下标的数据从刚才已经存储好的plist文件的数组中提取对应图片以及文本信息并设置给了self.imageView.image,使得单元格视图具有图片
总结:
在本次demo中,我们设置了网页导入,但是会阻碍进程的运行,使得设备运行时候会卡顿,因此,下一章节将会介绍多线程问题来解决UI更新和网络下载分别在主线程和子线程之间运行的多线程机制