第二次更新:更加丰富的相册图片展示


1.由于不在继承与FlowLayout,只是单纯继承与UIColletionLayout

2.关键方法 layoutAttributesForItemAtIndexPath 在返回的对应index返回需要布局的UICollectionViewLayoutAttributes属性即可

3.还是直接下载代码看自定义的Layout吧,有问题请留言,大过年的写的比较仓促

传送门

个人感觉CollectionView过于强大,基本什么界面都能用他来完成需求,只是如果自定义Layout的时候可能性能开销大。如果是普通的需求,他和tableView并没有多大的区别,同样都是通过datasource和delegate两个代理来进行用户交互稍微回顾下CollectionView的构成

1.Cells

2.Supplementary Views 追加视图 (sectionHeader or footer)

3.Decoration Views 装饰视图 (用作背景展示) 这货貌似还没怎么用过

另一方面,对于cell的组织方式和样式,确实由于collectionView比tableView要复杂的多,因此没有按照tableView的方式来定义,而是专门启用了一个布局类UICollectionViewlayout来对collectionView进行布局。废话不多说,系统自带的Layout已经是很常见了,今天写个自定义Layout来做些看起来还是蛮不错的Demo

正常人的Demo

先理论BB以下,不想看的请跳过

实现一个自定义Layout的正常做法就是继承与UICollectionViewlayout,然后重载以下方法,听我一一道来

三个必须手动重载的方法

1.-(CGSize)collectionViewContentSize返回可见区域内的大小2.-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect返回的是包含UICollectionViewlayoutAttributes对象的数组,该对象可以是cell,supplementary或装饰视图返回对应indexPath下cell的布局属性-(UICollectionViewLayoutAttributes _)layoutAttributesForItemAtIndexPath:(NSIndexPath _)indexPath返回对应indexpath下对应的追加视图属性 (没有可不重载)-(UICollectionViewLayoutAttributes _)layoutAttributesForSupplementaryViewOfKind:(NSString _)kind atIndexPath:(NSIndexPath *)indexPath返回对应indexpath下对应的追加视图属性 (没有可不重载)-(UICollectionViewLayoutAttributes * )layoutAttributesForDecorationViewOfKind:(NSString_)decorationViewKind atIndexPath:(NSIndexPath _)indexPath3.-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds当边界发生变化时,也就是滚动的时候,如果返回Yes,就是会一直调用,而且不断刷新重新计算布局信息
一个自动重载的方法-(void)prepareLayout一般在该方法中设定一些必要的layout的结构和初始需要的参数等。

注意:在需要更新layout时,需要给当前layout发送 -invalidateLayout,该消息会立即返回,并且预约在下一个loop的时候刷新当前layout,这一点和UIView的setNeedsLayout方法十分类似。在-invalidateLayout后的下一个collectionView的刷新loop中,又会从prepareLayout开始,依次再调用-collectionViewContentSize和-layoutAttributesForElementsInRect来生成更新后的布局。

Demo分析

1.简单的做个弹出的动画容器View 以下的self就是指弹出来的View,View上面给了一层underBackView,最终是在改View上面布局

// self是继承于UIView的,给上面的第一个View容器加个动画
- (void)showInSuperView:(UIView *)superView
{CAKeyframeAnimation *popAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];popAnimation.duration = 0.25;popAnimation.values = @[[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.1f, 0.1f, 1.0f)],[NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0f, 1.0f, 1.0f)]];popAnimation.keyTimes = @[@0.2f, @1.0f];popAnimation.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];// 在点击按钮的时候在改方法里面add到父视图上面去[superView addSubview:self];// 给View上面的容器View加动画[self.underBackView.layer addAnimation:popAnimation forKey:nil];
}

2.简单的懒加载布局视图以及一些回调delegate的设置就没必要多说了,大家都知道

#pragma mark - 懒加载
- (UIView *)underBackView
{if (_underBackView == nil) {_underBackView = [[UIView alloc] init];_underBackView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.8];_underBackView.originX = 30;_underBackView.originY = 60;_underBackView.width = SCREEN_WIDTH - 2 * _underBackView.originX;_underBackView.height = SCREEN_HEIGHT - 2 * _underBackView.originY;_underBackView.layer.cornerRadius = 5;_underBackView.layer.borderColor = [UIColor redColor].CGColor;_underBackView.layer.borderWidth = 2.0f;}return _underBackView;
}- (UILabel *)nameLabel
{if (_nameLabel == nil) {_nameLabel = [[UILabel alloc] init];_nameLabel.textAlignment = NSTextAlignmentCenter;_nameLabel.backgroundColor = [UIColor whiteColor];_nameLabel.font = [UIFont boldSystemFontOfSize:20];_nameLabel.textColor = [UIColor blueColor];_nameLabel.layer.cornerRadius = 5.0f;_nameLabel.layer.borderColor = [UIColor blackColor].CGColor;_nameLabel.layer.borderWidth = 2.0f;}return _nameLabel;
}- (UIButton *)selectedButton
{if (_selectedButton == nil) {_selectedButton = [UIButton buttonWithType:UIButtonTypeCustom];_selectedButton.backgroundColor = [UIColor blackColor];[_selectedButton setTitle:@"选这个" forState:UIControlStateNormal];[_selectedButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];[_selectedButton addTarget:self action:@selector(chooseDone:) forControlEvents:UIControlEventTouchUpInside];_selectedButton.layer.cornerRadius = 20.0f;_selectedButton.layer.borderWidth = 2.0f;_selectedButton.layer.borderColor = [UIColor whiteColor].CGColor;}return _selectedButton;
}
- (void)chooseDone:(UIButton *)button
{if (self.delegate && [self.delegate respondsToSelector:@selector(selectedHero:)]) {[self.delegate selectedHero:self.dataSource[_selectedIndex]];}
}- (UIButton *)closeButton
{if (_closeButton == nil) {_closeButton = [UIButton buttonWithType:UIButtonTypeCustom];_closeButton.backgroundColor = [UIColor redColor];[_closeButton setImage:[UIImage imageNamed:@"close"] forState:UIControlStateNormal];[_closeButton addTarget:self action:@selector(close:) forControlEvents:UIControlEventTouchUpInside];}return _closeButton;
}- (void)close:(UIButton *)button
{if (self.delegate && [self.delegate respondsToSelector:@selector(closePopView)]) {[self.delegate closePopView];}
}
- (UICollectionView *)collectionView
{if (_collectionView == nil) {MKJCollectionViewFlowLayout *flow = [[MKJCollectionViewFlowLayout alloc] init];flow.scrollDirection = UICollectionViewScrollDirectionHorizontal;flow.itemSize = CGSizeMake(self.underBackView.width / 2, self.underBackView.width - 100);flow.minimumLineSpacing = 30;flow.minimumInteritemSpacing = 30;flow.needAlpha = YES;flow.delegate = self;CGFloat oneX =self.underBackView.width / 4;flow.sectionInset = UIEdgeInsetsMake(0, oneX, 0, oneX);_collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 30, self.underBackView.bounds.size.width, self.underBackView.bounds.size.height * 0.65) collectionViewLayout:flow];_collectionView.backgroundColor = [UIColor whiteColor];_collectionView.delegate = self;_collectionView.dataSource = self;_collectionView.showsHorizontalScrollIndicator = NO;[_collectionView registerNib:[UINib nibWithNibName:indentify bundle:nil] forCellWithReuseIdentifier:indentify];}return _collectionView;
}

3.关键是还是要看最终自定义的FlowLayout一些小东西的实现

重载的方法和方式在上面都已经理论了一番了,需要的自己去上面看看

第一个效果:需要一个放大的效果和透明的效果 

// 重载第一个方法
// 返回可见区域的的内容尺寸
- (CGSize)collectionViewContentSize
{return [super collectionViewContentSize];
}// 重载方法第二个
// 返回rect中所有元素的布局属性
// 返回的是包含UICollectionViewLayoutAttributes的NSArray
// UICollectionViewAttributes可以是cell,追加视图以及装饰视图的信息,通过以下三个不同的方法可以获取到不同类型的UICollectionViewLayoutAttributes属性
// layoutAttributesForCellWithIndexPath:  返回对应cell的UICollectionViewAttributes布局属性
// layoutAtttibutesForSupplementaryViewOfKind:withIndexPath: 返回装饰的布局属性 如果没有追加视图可不重载
// layoutAttributesForDecorationViewOfKind:withIndexPath: 返回装饰的布局属性  如果没有可以不重载
- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect
{//1. 获取可见区域CGRect visibleRect = CGRectMake(self.collectionView.contentOffset.x, 0, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);//2. 获得这个区域的itemNSArray *visibleItemArray = [super layoutAttributesForElementsInRect:visibleRect];//3. 遍历,让靠近中心线的item方法,离开的缩小for (UICollectionViewLayoutAttributes *attributes in visibleItemArray){//1. 获取每个item距离可见区域左侧边框的距离 有正负CGFloat leftMargin = attributes.center.x - self.collectionView.contentOffset.x;//2. 获取边框距离屏幕中心的距离(固定的)CGFloat halfCenterX = self.collectionView.frame.size.width / 2;//3. 获取距离中心的的偏移量,需要绝对值CGFloat absOffset = fabs(halfCenterX - leftMargin);//4. 获取的实际的缩放比例 距离中心越多,这个值就越小,也就是item的scale越小 中心是方法最大的CGFloat scale = 1 - absOffset / halfCenterX;//5. 缩放attributes.transform3D = CATransform3DMakeScale(1 + scale * MKJMinZoomScale, 1 + scale * MKJMinZoomScale, 1);// 是否需要透明if (self.needAlpha){if (scale < 0.6){attributes.alpha = 0.6;}else if (scale > 0.99){attributes.alpha = 1.0;}else{attributes.alpha = scale;}}}NSArray *attributesArr = [[NSArray alloc] initWithArray:visibleItemArray copyItems:YES];return attributesArr;
}

第二个效果:如何让滚动的的item根据中心距离,自动居中对齐,避免滚动到哪停到哪

这里做了第一个和最后一个的判断,不然在头和尾会出现对不齐的情况

// 重载第四个属性,item自动中心对齐
// 该方法可写可不写,主要是让滚动的item根据距离中心的值,确定哪个必须展示在中心,不会像普通的那样滚动到哪里就停到哪里
- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity
{// ProposeContentOffset是本来应该停下的位子// 1. 先给一个字段存储最小的偏移量 那么默认就是无限大CGFloat minOffset = CGFLOAT_MAX;// 2. 获取到可见区域的centerXCGFloat horizontalCenter = proposedContentOffset.x + self.collectionView.bounds.size.width / 2;// 3. 拿到可见区域的rectCGRect visibleRec = CGRectMake(proposedContentOffset.x, 0, self.collectionView.bounds.size.width, self.collectionView.bounds.size.height);// 4. 获取到所有可见区域内的item数组NSArray *visibleAttributes = [super layoutAttributesForElementsInRect:visibleRec];// 遍历数组,找到距离中心最近偏移量是多少for (UICollectionViewLayoutAttributes *atts in visibleAttributes){// 可见区域内每个item对应的中心X坐标CGFloat itemCenterX = atts.center.x;// 比较是否有更小的,有的话赋值给minOffsetif (fabs(itemCenterX - horizontalCenter) <= fabs(minOffset)) {minOffset = itemCenterX - horizontalCenter;}}// 这里需要注意的是  上面获取到的minOffset有可能是负数,那么代表左边的item还没到中心,如果确定这种情况下左边的item是距离最近的,那么需要左边的item居中,意思就是collectionView的偏移量需要比原本更小才是,例如原先是1000的偏移,但是需要展示前一个item,所以需要1000减去某个偏移量,因此不需要更改偏移的正负// 但是当propose小于0的时候或者大于contentSize(除掉左侧和右侧偏移以及单个cell宽度)  、// 防止当第一个或者最后一个的时候不会有居中(偏移量超过了本身的宽度),直接卡在推荐的停留位置CGFloat centerOffsetX = proposedContentOffset.x + minOffset;if (centerOffsetX < 0) {centerOffsetX = 0;}if (centerOffsetX > self.collectionView.contentSize.width -(self.sectionInset.left + self.sectionInset.right + self.itemSize.width)) {centerOffsetX = floor(centerOffsetX);}return CGPointMake(centerOffsetX, proposedContentOffset.y);
}

第三个效果:如何让视图滚动的时候(不触发点击事件),自动把滚动到第几个的图片展示出来(delegate)

CGPoint pInView = [self.collectionView.superviewconvertPoint:self.collectionView.centertoView:self.collectionView];

同学如果你无法理解上面的坐标转换可以点击以下传送门,帮你快速理解

点击打开链接我要学习

// 重载第三个属性
// 滚动的时候会一直调用
// 当边界发生变化的时候,是否应该刷新布局。如果YES那么就是边界发生变化的时候,重新计算布局信息  这里的newBounds变化的只有x值的变化,也就是偏移量的变化
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
{// 把collectionView的父视图(underBackView)上的中心坐标,转换到整个CollectionView ContentSize中的坐标 根据point来计算对应的indexpathCGPoint pInView = [self.collectionView.superview convertPoint:self.collectionView.center toView:self.collectionView];// 通过坐标获取对应的indexpathNSIndexPath *indexPathNow = [self.collectionView indexPathForItemAtPoint:pInView];if (indexPathNow.row == 0){if (newBounds.origin.x < SCREEN_WIDTH / 2){if (_index != indexPathNow.row){_index = 0;if (self.delegate && [self.delegate respondsToSelector:@selector(collectioViewScrollToIndex:)]){[self.delegate collectioViewScrollToIndex:_index];}}}}else{if (_index != indexPathNow.row){_index = indexPathNow.row;if (self.delegate && [self.delegate respondsToSelector:@selector(collectioViewScrollToIndex:)]){[self.delegate collectioViewScrollToIndex:_index];}}}[super shouldInvalidateLayoutForBoundsChange:newBounds];return YES;
}

第四个效果:点击Item,自动中心对齐

// 点击item的时候
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{// 这里的坐标相互转换 可看我写的另一个小博客CGPoint pInUnderView = [self.underBackView convertPoint:collectionView.center toView:collectionView];// 获取中间的indexpathNSIndexPath *indexpathNew = [collectionView indexPathForItemAtPoint:pInUnderView];if (indexPath.row == indexpathNew.row){NSLog(@"点击了同一个");return;}else{// 点击不同就把点击的滚动到中心居中[self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];}
}

主要的一些方法和实现思路都已经介绍完了,小白写的Demo,大神勿喷,理解的同学可以自己试试

Demo地址:点击打开链接

Demo写的很仓促,有些细节还没做的很好,只是玩英雄联盟选择皮肤的时候突然想到要写一个试试,各位有什么问题可以留言,我会慢慢更正能阅读完博主的文章也是不容易,谢谢捧场,好人一生平安,博主会不断进步的,谢谢

 

iOS卡片式立体轮播仿英雄联盟选择皮肤效果展示相关推荐

  1. NGUI的图片轮播类似英雄联盟选皮肤的小DEMO

    周末 无事 看了 一英雄联盟的那个选择皮肤的 轮播图片 觉得 原理很简单 就像实现下 1,在边角放几张层叠的图片,暂且叫图片堆吧,尽量让它有3d的层次感 2,点击最上面的一张,堆顶图片一边移动到中间, ...

  2. 【NGUI】Unity实现英雄联盟选择皮肤效果

    using UnityEngine; using System.Collections; /// <summary> /// 脚本位置:Card预制体身上 /// 脚本功能:保存Card所 ...

  3. ES6公用立体轮播组件的封装及使用

    ES6公用立体轮播组件的封装及使用 源码github链接:https://github.com/XieTongXue/how-to/tree/master/carousel-3d 1.效果展示 2.容 ...

  4. ViewFlipper实现文字轮播(仿淘宝头条垂直滚动广告)

    ViewFlipper实现文字轮播(仿淘宝头条垂直滚动广告) 广告条目可以单独写成布局文件,然后在布局文件或者代码中添加到总布局中 从源码可以看出,其实ViewFlipper间接的继承了FrameLa ...

  5. ios ScrollerView之图片轮播器

    ios ScrollerView之图片轮播器 今天项目中用到了图片轮播器,写完之后贴到博客里来记录一下,也方便有兴趣的同学学习 #import "JYHCarouselController. ...

  6. DIV布局——仿英雄联盟LOL首页(11页) 大学生简单个人静态HTML网页设计作品 DIV布局个人介绍网页模板代码 DW学生个人网站制作成品下载

    HTML5期末大作业:仿英雄联盟网站设计--仿英雄联盟LOL首页(11页) 大学生简单个人静态HTML网页设计作品 DIV布局个人介绍网页模板代码 文章目录 HTML5期末大作业:仿英雄联盟网站设计- ...

  7. web网页设计期末课程大作业~超高仿英雄联盟LOL游戏官网设计与实现(HTML+CSS+JavaScript)...

    仿英雄联盟LOL游戏官网设计与实现(HTML+CSS+JavaScript) 关于HTML期末网页制作,大作业A+水平 ~游戏网页作业HTML+CSS+JavaScript实现,共有游戏首页 等页面! ...

  8. 逼真版仿英雄联盟纯html+css+jqueryLOL网页版

    前言: 为了提高自己的编码兴趣,最近使用html,css,JQuery做了一个仿版的<英雄联盟>,虽然自己主修的是后端,但是技多压身.纯属也是自己的一个兴趣.上一节简单的介绍了仿版的< ...

  9. 仿英雄联盟比赛直播网页模板

    介绍: 高仿英雄联盟2017全球决赛官方比赛直播模板,带直播视频.排行榜.赛程列表等等功能. 网盘下载地址: http://kekewl.net/NbiX1vJoyjU0 图片:

最新文章

  1. onbeforedunload事件
  2. python怎么打开shell界面-使用IDLE的Python shell窗口实例详解
  3. 做向量召回 All You Need is 双塔
  4. 字节跳动测试开发4轮面试_字节跳动2018招聘测试开发方向(第四批)
  5. 在Windows下使用OpenCL配置
  6. space index.php 7-14,SpacePack高效部署PHP生产环境
  7. Android SurfaceFlinger vsync信号产生与分发
  8. 今天我的生日,纪念一下
  9. python tkinter 窗口位置_Python tkinter调整元件在窗口中的位置与几何布局管理
  10. 华为hcie题库有多少题?华为认证hcie面试需要注意什么?
  11. Python常用的设计模式
  12. 方便好用的论文管理软件EndNote X9 + PDF阅读编辑器Adobe Acrobat DC(2)
  13. 荣耀手机动态修改手机型号参数
  14. 你真的了解“无纸化办公”了吗?
  15. 思科交换机的基础操作命令有这些!
  16. 浅谈大型互联网的企业入/侵及防护策略
  17. 树莓派采集MPU9250运行AHRS进行姿态解算
  18. 在项目中使用iconfont图标(在线使用)
  19. 高仿小米商城项目,我爱了!
  20. 系统的认识大数据人工智能数据分析中的数据

热门文章

  1. Photoshop 之利用 调整边缘 抠图
  2. php拆词,关于php:将句子拆分成单独的单词
  3. 【简单好玩】细胞自动机小游戏
  4. Css---去除点击表单输入框后出现的原生边框
  5. c语言中free函数_free()函数与C ++中的示例
  6. nohup怎么更改名字_5个更改过姓名的汽车品牌,宝马、雷克萨斯都在列,曾用名惹人笑...
  7. SNS中好友动态功能的设计思路
  8. 雅虎天气的图片URL格式
  9. Python音视频开发:消除抖音短视频Logo和去电视台标
  10. 信号完整性基础02:从电感、电容到理想传输线(1)