UICollectionView 的研究之二 :自定义 UICollectionViewFlowLayout

本文主要是介绍UICollectionView 的研究之二 :自定义 UICollectionViewFlowLayout,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

UICollectionView 实现各式复杂布局核心在于 UICollectionViewLayout,需要我们去自定义实现。

通过各种layout 的自定义实现,以及它们之间的切换。可以实现一些酷炫的布局,例如

(图片选自:http://www.cnblogs.com/markstray/p/5822262.html)

Cover Flow 布局

堆叠布局


圆形布局


关于需要重写方法的描述

自定义布局需要重写以下四个方法

(文字描述取自:https://www.cnblogs.com/wangliang2015/p/5388658.html 和 https://www.cnblogs.com/hissia/p/5723629.html):

 - 作用:在这个方法中做一些初始化操作

 - 注意:子类重写prepareLayout,一定要调用[super prepareLayout]

 - (void)prepareLayout;



 - 作用:

 - 这个方法的返回值是个数组

 - 这个数组中存放的都是UICollectionViewLayoutAttributes对象

 - UICollectionViewLayoutAttributes对象决定了cell的排布方式(frame等)

- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect;


 - 作用:如果返回YES,那么collectionView显示的范围发生改变时,就会重新刷新布局

 - 一旦重新刷新布局,就会按顺序调用下面的方法:

 - prepareLayout

 - layoutAttributesForElementsInRect:

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds;

- 作用:返回值决定了collectionView停止滚动时最终的偏移量(contentOffset)

 - 参数:

 - proposedContentOffset:原本情况下,collectionView停止滚动时最终的偏移量

 - velocity:滚动速率,通过这个参数可以了解滚动的方向

-(CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity;


具体实现逻辑

以 Cover Flow 布局的实现为例子进行阐述


进行初始化

- (instancetype)init {if (self = [super init]) {}return self;
}

进行布局,并且 collectionView 显示 rect 改变是进行布局刷新

- (void)prepareLayout {[super prepareLayout];// 水平滚动self.scrollDirection = UICollectionViewScrollDirectionHorizontal;// 决定第一张图片所在的位置CGFloat margin = (self.collectionView.frame.size.width - self.itemSize.width) / 2;self.collectionView.contentInset = UIEdgeInsetsMake(0, margin, 0, margin);
}- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {return YES;
} // return YES to cause the collection view to requery the layout for geometry information

该方法是进行自定义的核心,在这里写各种算法以达成想要的效果

该例子中,我们要实现的效果是在滑动的过程中,item 逐渐接近中心,会逐步增大,直到显示最大值,之后不断远离中心点,item 逐步缩小。这一效果类似于三角函数中的正、余弦函数。初步锁定这两个函数,而要选择哪一个?

在滑动的过程中,我们可以得到

self.collectionView.contentOffset.x :这是内容最左侧相对于 collectionView 最左侧的偏移值

attributes.center.x :这是当前 item 的水平中心点,该 x 值是从内容的最左侧算起,直到当前 item 的水平中心点的,全部加起来就是该 item 的水平中心 x。


再者,无论是否滑动,都有一个固定值:

self.collectionView.center.x :位于屏幕水平方向的中心不变,大小不变。



那么,以第一个item 进行分析,self.collectionView.contentOffset.x 与 self.collectionView.contentOffset.的差值与屏幕中心 x 相减的绝对值为item 中心与屏幕中心之间的距离

    

              屏幕中心与item 中心相距为0                                 屏幕中心与item 中心相距40

由此,我们选择余弦函数进行计算。

- (nullable NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {// 闪屏现象解决参考 :https://blog.csdn.net/u013282507/article/details/53103816//扩大控制范围,防止出现闪屏现象rect.size.width = rect.size.width + KScreenWidth;rect.origin.x = rect.origin.x - KScreenWidth/2;// 让父类布局好样式NSArray *arr = [[NSArray alloc] initWithArray:[super layoutAttributesForElementsInRect:rect] copyItems:YES];for (UICollectionViewLayoutAttributes *attributes in arr) {CGFloat scale;
//        scale = 1.0;// collectionView 的 centerXCGFloat centerX = self.collectionView.center.x;CGFloat step = ABS(centerX - (attributes.center.x - self.collectionView.contentOffset.x));NSLog(@"step %@ : attX %@ - offset %@", @(step), @(attributes.center.x), @(self.collectionView.contentOffset.x));scale = fabsf(cosf(step/centerX * M_PI/5));attributes.transform = CGAffineTransformMakeScale(scale, scale);}return arr;
} // return an array layout attributes instances for all the views in the given rect

确保在滚动结束的时候的显示效果,此处确保某一个item 滚动结束时是居中显示的。

- (CGPoint)targetContentOffsetForProposedContentOffset:(CGPoint)proposedContentOffset withScrollingVelocity:(CGPoint)velocity {// 保证滚动结束后视图的显示效果// 计算出最终显示的矩形框CGRect rect;rect.origin.y = 0;rect.origin.x = proposedContentOffset.x;rect.size = self.collectionView.frame.size;// 获得 super 已经计算好的布局的属性NSArray *arr = [super layoutAttributesForElementsInRect:rect];// 计算 collectionView 最中心点的 x 值CGFloat centerX = proposedContentOffset.x + self.collectionView.frame.size.width * 0.5;CGFloat minDelta = MAXFLOAT;for (UICollectionViewLayoutAttributes *attrs in arr) {if (ABS(minDelta) > ABS(attrs.center.x - centerX)) {minDelta = attrs.center.x - centerX;}}proposedContentOffset.x += minDelta;return proposedContentOffset;
} // return a point at which to rest after scrolling - for layouts that want snap-to-point scrolling behavior

代码地址:https://download.csdn.net/download/u013410274/10356732

所有的参考链接:

WWDC 2012 Session 笔记 -- 205 Introducing Collection Views

http://www.cnblogs.com/markstray/p/5822262.html

UICollectionViewLayout 继承 UICollectionViewFlowLayout 自定义布局

https://www.cnblogs.com/wangliang2015/p/5388658.html

自定义流水布局(UICollectionViewFlowLayout 的基本使用)

https://www.cnblogs.com/hissia/p/5723629.html

iOS 利用余弦函数实现卡片浏览工具

https://blog.csdn.net/u013282507/article/details/53103816


这篇关于UICollectionView 的研究之二 :自定义 UICollectionViewFlowLayout的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1142496

相关文章

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

如何自定义Nginx JSON日志格式配置

《如何自定义NginxJSON日志格式配置》Nginx作为最流行的Web服务器之一,其灵活的日志配置能力允许我们根据需求定制日志格式,本文将详细介绍如何配置Nginx以JSON格式记录访问日志,这种... 目录前言为什么选择jsON格式日志?配置步骤详解1. 安装Nginx服务2. 自定义JSON日志格式各

Android自定义Scrollbar的两种实现方式

《Android自定义Scrollbar的两种实现方式》本文介绍两种实现自定义滚动条的方法,分别通过ItemDecoration方案和独立View方案实现滚动条定制化,文章通过代码示例讲解的非常详细,... 目录方案一:ItemDecoration实现(推荐用于RecyclerView)实现原理完整代码实现

基于Spring实现自定义错误信息返回详解

《基于Spring实现自定义错误信息返回详解》这篇文章主要为大家详细介绍了如何基于Spring实现自定义错误信息返回效果,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录背景目标实现产出背景Spring 提供了 @RestConChina编程trollerAdvice 用来实现 HTT

SpringSecurity 认证、注销、权限控制功能(注销、记住密码、自定义登入页)

《SpringSecurity认证、注销、权限控制功能(注销、记住密码、自定义登入页)》SpringSecurity是一个强大的Java框架,用于保护应用程序的安全性,它提供了一套全面的安全解决方案... 目录简介认识Spring Security“认证”(Authentication)“授权” (Auth

SpringBoot自定义注解如何解决公共字段填充问题

《SpringBoot自定义注解如何解决公共字段填充问题》本文介绍了在系统开发中,如何使用AOP切面编程实现公共字段自动填充的功能,从而简化代码,通过自定义注解和切面类,可以统一处理创建时间和修改时间... 目录1.1 问题分析1.2 实现思路1.3 代码开发1.3.1 步骤一1.3.2 步骤二1.3.3

dubbo3 filter(过滤器)如何自定义过滤器

《dubbo3filter(过滤器)如何自定义过滤器》dubbo3filter(过滤器)类似于javaweb中的filter和springmvc中的intercaptor,用于在请求发送前或到达前进... 目录dubbo3 filter(过滤器)简介dubbo 过滤器运行时机自定义 filter第一种 @A

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

CSS自定义浏览器滚动条样式完整代码

《CSS自定义浏览器滚动条样式完整代码》:本文主要介绍了如何使用CSS自定义浏览器滚动条的样式,包括隐藏滚动条的角落、设置滚动条的基本样式、轨道样式和滑块样式,并提供了完整的CSS代码示例,通过这些技巧,你可以为你的网站添加个性化的滚动条样式,从而提升用户体验,详细内容请阅读本文,希望能对你有所帮助...

关于Java内存访问重排序的研究

《关于Java内存访问重排序的研究》文章主要介绍了重排序现象及其在多线程编程中的影响,包括内存可见性问题和Java内存模型中对重排序的规则... 目录什么是重排序重排序图解重排序实验as-if-serial语义内存访问重排序与内存可见性内存访问重排序与Java内存模型重排序示意表内存屏障内存屏障示意表Int