非常抱歉,在写这个之前有必要去稍微的介绍一下UICollectionView,当然大家可以直接看代码实现哈~~~~
UICollectionView初识
- UICollectionView 是iOS6 新引进的API,用于展示集合视图,布局更加灵活,可以通过自定义布局达到没有做不到只有想不到的效果,用法类似于UITableView
- 既然类似UITableView,那么它也就自带了缓存机制,性能上也是没的说
- 目前很多应用的很多页面,比如类似九宫格、类似tableView、类似ScrollView的图片轮播器等等效果都完全可能是使用的CollectionView展示的
- 而且自从iOS9之后,苹果更是更新了它的API,通过设置它的一些代理方法,就可以轻松实现类似支付宝首页那种按钮拖拽移动换位的效果
综上所述:目前CollectionView已经大量入侵App,学会使用它而且要像使用UITableView使用一样熟练使用它是非常非常非常有必要的
实现新特性页面前的一些简单铺垫
- 以前我们实现新特性页面无疑是使用的UIScrollview,它就像图片轮播器的效果差不多,只不过每一个imageView的尺寸变的跟屏幕尺寸一样大了
- 普通的使用UIScrollview,那么就是需要展示几张图片就创建几个UIImageView,这样我们就会去思考如何让当前没有显示在眼前的imageView和UITableView的cell一样有缓存机制,让imageView复用呢
- 带着上一个问题,就有了目前比较流行的使用3个或者2个UIImageView实现多张图片的轮播器效果,这样确实可以让imageView复用,但是缓存机制需要我们自己去实现
- OK,在上述情况下,使用CollectionView实现轮播器效果就应运而生了,自带有缓存机制,而且也不需要我们自己写复杂的布局计算,直接使用系统提供的流水布局就可以了,下面开始上代码了
具体的代码实现
1)自定义一个继承自UICollectionViewController的类
LBNewFeatureViewController
2)由于collectionView的cell没有像tableView的cell一样里面自带一些子控件,所以我们还需要自定义一个继承自UICollectionViewCell的子类,
LBNewFetureCell
里面添加一个UIImageView,用以展示新特性图片
@interface LBNewFetureCell ()
/** item上的图片 */
@property (nonatomic, weak)UIImageView *itemImageView ;
@end
3)一般情况下,新特性页面都是需要在当前版本号大于之前保存的版本号的时候展示,所以在外界需要使用到它,创建它的时候,我们就需要初始化它的layout
//一般我们都是在LBNewFetureViewController.m文件中模仿苹果
//就像我们在使用xib描述控制器view的时间,使用initWithNibName:...
- (instancetype)init
{
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
//layout里面的属性设置直接影响的就是cell的相关属性
// cell的尺寸就是由布局属性决定的
layout.itemSize = [UIScreen mainScreen].bounds.size;
//由于设置的是新特性页面,是需要左右滚动,而且页面之间没有间距
layout.minimumLineSpacing = 0;
layout.minimumInteritemSpacing = 0;
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
//让CollectionView使用我们经过配置的layout
return [self initWithCollectionViewLayout:layout];
}
4)对collectionView的一些基本配置
static NSString * const reuseIdentifier = @"newFeature";
- (void)viewDidLoad {
[super viewDidLoad];
//注册cell,collectionView的cell 只可以注册,不可以通过alloc init方法创建
[self.collectionView registerClass:[LBNewFetureCell class] forCellWithReuseIdentifier:reuseIdentifier];
//让collectionView支持翻页
self.collectionView.pagingEnabled = YES;
//让collectionView隐藏水平、垂直滚动条,这个可以根据对应需求自己设置
self.collectionView.showsVerticalScrollIndicator = NO;
self.collectionView.showsHorizontalScrollIndicator = NO;
//让collectionView隐藏弹簧效果
self.collectionView.bounces = NO;
}
4)设置好layout之后,就需要跟tableview去实现它的相关数据源和代理方法,由于我们是继承UICollectionViewController,所以不再需要自己设置数据源、代理
#pragma mark <UICollectionViewDataSource>
//collectionView每组多少行,我们这里就需要一组,MaxItemCount是我定义的宏,就是新特性页面需要展示几个页面
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return MaxItemCount;
}
//这个方法和tabbleView里面的cellForRow方法一样
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
LBNewFetureCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
// 这里算是一个关键,我给cell定义了一个index属性,目的是希望通过当前方法传递过来的indexPath,重写index的set方法去给对应的image赋值
// 屏蔽具体的赋值操作,把这些操作封装到cell内部
cell.index = (int)indexPath.item;
return cell;
}
//这个方法就是当一个cell完全展示的时候调用,因为我们新特性页面一个cell就是一个页面,所以这个方法用到我们新特性页面是非常巧妙的
#pragma mark <UICollectionViewDelegate>
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
//indexPathsForVisibleItems这个是collectionView返回给我们的一个数组
//这个数组里面存放的就是当前展示在我们眼前的cell,我们是新特性页面,所以这个数组每次就只有一个cell
//通过这个数组拿到它里面的唯一的一个对象,就是当前展示在我们眼前的新特性页面对应的cell
NSIndexPath *speIndexPath = collectionView.indexPathsForVisibleItems.lastObject;
// 通过上面获得到的indexPath,我们拿到对应的cell
LBNewFetureCell *newCell = (LBNewFetureCell *)[collectionView cellForItemAtIndexPath:speIndexPath];
//判断当前展示的cell如果是新特性页面的最后一个页面,那么就执行控制器的跳转,跳转到应用的首页,一般都是tabBarController
if (speIndexPath.item == (MaxItemCount - 1)) {
//执行控制器跳转,cell专门提供给外界一个switchMainController方法,用做控制器跳转
[newCell switchMainController];
}
}
5)这个里面是自定义cell的一些实现
LBNewFetureCell.h
@interface LBNewFetureCell : UICollectionViewCell
/** item的索引 */
@property(nonatomic,assign)int index;
/**
* 当cell滑动到最后一个时调用
*/
- (void)switchMainController;
@end
LBNewFetureCell.m
#import "LBNewFetureCell.h"
@interface LBNewFetureCell ()
/** item上的图片 */
@property (nonatomic, weak)UIImageView *itemImageView ;
/** 跳转按钮 */
@property (nonatomic, weak) UIButton *switchBtn ;
@end
@implementation LBNewFetureCell
#pragma mark - 懒加载跳转按钮
- (UIButton *)switchBtn
{
if (!_switchBtn) {
UIButton *btn =[[UIButton alloc] init];
[btn setBackgroundImage:[UIImage imageNamed:@"Start"] forState:UIControlStateNormal];
//按钮自适应大小
[btn sizeToFit];
[btn addTarget:self action:@selector(switchBtnClick) forControlEvents:UIControlEventTouchUpInside];
[self.contentView addSubview:btn];
self.switchBtn = btn;
}
return _switchBtn;
}
#pragma mark - 懒加载cell的imageview
-(UIImageView *)itemImageView
{
if (!_itemImageView) {
UIImageView *itemImageView=[[UIImageView alloc]init];
_itemImageView = itemImageView;
[self.contentView addSubview:_itemImageView];
}
return _itemImageView;
}
#pragma mark - 布局cell上面的子控件位置
- (void)layoutSubviews
{
[super layoutSubviews];
_itemImageView.frame = self.bounds;
CGFloat centerX = self.bounds.size.width * 0.5;
CGFloat centerY = CGRectGetMaxY(self.bounds) - 180;
self.switchBtn.center = CGPointMake(centerX, centerY);
}
#pragma mark - 重写index的set方法
- (void)setIndex:(int)index
{
_index = index;
NSString *imageName = [NSString stringWithFormat:@"start%dBackground",index+1];
self.itemImageView.image = [UIImage imageNamed:imageName];
self.switchBtn.transform=CGAffineTransformMakeTranslation(0, self.bounds.size.height);
}
#pragma mark - 弹出跳转控制器按钮(动画效果)
- (void)switchMainController
{
[UIView animateWithDuration:.8f delay:0 usingSpringWithDamping:.7f initialSpringVelocity:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
//动画结束,Btn回归原始位置
self.switchBtn.transform=CGAffineTransformIdentity;
} completion:nil];
}
#pragma mark - 点击跳转控制器按钮
- (void)switchBtnClick
{
//这里我没有采用拿到窗口去执行跳转的方法,采用的是发送了一个通知去进行跳转
NSNotification *note=[NSNotification notificationWithName:@"switchMainController" object:self userInfo:nil];
//发送通知
[[NSNotificationCenter defaultCenter] postNotification:note];
}
OK,基本进行到这里,这个功能大致就实现了,UICollectionView还有很多很多东西没有涉及到,这里只是初识,后续还会对于这个进行稍微深入一点的使用讲解,感谢,希望大家都可以掌握这个强大控件的使用