- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章详解iOS 滚动视图的复用问题解决方案由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
lazyscroll是什么 。
lazyscrollview 继承自scrollview,目标是解决异构(与tableview的同构对比)滚动视图的复用回收问题。它可以支持跨view层的复用,用易用方式来生成一个高性能的滚动视图.
为什么要用lazyscrollview 。
我们在做首页的时候,往往展示的东西会很多,随着view数量逐渐膨胀,没有一套复用回收机制的scrollview已经影响到性能了,迫切需要处理对scrollview中view的复用和回收。使用tableview只能用来解决同类cell的展示,然而在实际的场景中在scrollview里面,view的种类往往会比较多,所以使用tableview不适合我们的场景。 而uicollectionview本身的布局和复用回收机制不够灵活,用起来也较为繁琐。所以诞生了lazyscrollview去解决这个问题。这也是天猫ios客户端的首页落地方案.
lazyscroll使用 。
lazyscrollview的使用和tableview很像,不过多了一个需要实现的方法:返回对应index的view 相对lazyscrollview的绝对坐标.
实现lazyscrollviewdatasource 。
类似tableview的用法,我们需要使用方实现lazyscrollviewdatasource的delegate.
1
2
3
4
5
6
7
8
|
@protocol tmmuilazyscrollviewdatasource <nsobject>
@required
//scrollview展示item个数
- (nsuinteger)numberofiteminscrollview:(tmmuilazyscrollview *)scrollview;
//要求根据index直接返回rectmodel
- (tmmuirectmodel *)scrollview:(tmmuilazyscrollview *)scrollview rectmodelatindex:(nsuinteger)index;
//返回下标所对应的view
- (uiview *)scrollview:(tmmuilazyscrollview *)scrollview itembymuiid:(nsstring *)muiid;
|
lazyscrollview的核心是在初始状态就得知所有view应该显示的位置。第一个方法很简单,获取lazyscrollview中item的个数。第二个方法需要按照index返回tmmuirectmodel ,它会携带对应index的view 相对lazyscrollview的绝对坐标.
这里出现了一个tmmuirectmodel ,这是个什么东西呢?我们看一下代码:
1
2
3
4
5
|
@interface tmmuirectmodel:nsobject
//转换后的绝对值rect
@property (nonatomic,assign) cgrect absrect;
//业务下标
@property (nonatomic,copy) nsstring *muiid;
|
这里有两个属性,absrect是lazyscroll中的view相对lazyscrollview的绝对坐标,muiid是这个view在lazyscrollview中唯一的标识符,可赋值也可不赋值.
第三个方法,返回view.
@interface uiview(tmmui) 。
1
2
3
4
|
//索引过的标识,在lazyscrollview范围内唯一
@property (nonatomic, copy) nsstring *muiid;
//重用的id
@property (nonatomic, copy) nsstring *reuseidentifier;
|
首先,我们在uiview之外加了一个category,这个category可以让view携带muiid和reuseidentifier,对于返回的view来说,只需要在乎对view的reuseidentifier赋值,muiid的赋值会在lazyscrollview中处理掉。reuseidentifier相同的view会被复用,如果这个view的reuseidentifier是nil或者空字符串,则不会被复用.
lazyscrollview内部原理分析 。
首先来看一个简单的案例:
根据datasource获取所有的tmmuirectmodel 。
根据datasource的delegate,拿到所有的view应该被显示的位置。这一步,核心是拿到的位置是确定的。根据demo,我们观察从 0/1 - 2/3 之间这些view,这个时候lazyscrollview拿到的rect如下:
。
index | 标号(muiid) | rect |
---|---|---|
0 | 0/0 | origin = (x = 25, y = 15), size = (width = 156, height = 150 |
1 | 0/1 | origin = (x = 194, y = 15), size = (width = 156, height = 150) |
2 | 0/2 | origin = (x = 25, y = 180), size = (width = 156, height = 150) |
3 | 0/3 | origin = (x = 194, y = 180), size = (width = 156, height = 150 |
4 | 1/0 | origin = (x = 5, y = 360), size = (width = 177.5, height = 150) |
5 | 1/1 | origin = (x = 192.5, y = 426), size = (width = 84, height = 84) |
6 | 1/2 | origin = (x = 192.5, y = 360), size = (width = 177.5, height = 56) |
7 | 1/3 | origin = (x = 286.5, y = 426), size = (width = 83.5, height = 84) |
8 | 2/0 | origin = (x = 25, y = 530), size = (width = 325, height = 150) |
9 | 2/1 | origin = (x = 25, y = 695), size = (width = 325, height = 150) |
10 | 2/2 | origin = (x = 25, y = 860), size = (width = 325, height = 150) |
。
排序 。
拿到了这些位置之后,接下来做的事情就是排序。排序生成的索引会有两个:根据顶边(y)升序排序的索引和根据底边(y+height)降序排序的索引.
根据顶边(y)升序排序的索引 。
。
index | 标号(muiid) | rect |
---|---|---|
0 | 0/0 | origin = (x = 25, y = 15), size = (width = 156, height = 150 |
1 | 0/1 | origin = (x = 194, y = 15), size = (width = 156, height = 150) |
2 | 0/2 | origin = (x = 25, y = 180), size = (width = 156, height = 150) |
3 | 0/3 | origin = (x = 194, y = 180), size = (width = 156, height = 150 |
4 | 1/0 | origin = (x = 5, y = 360), size = (width = 177.5, height = 150) |
5 | 1/1 | origin = (x = 192.5, y = 360), size = (width = 177.5, height = 56) |
6 | 1/2 | origin = (x = 192.5, y = 360), size = (width = 177.5, height = 56) |
7 | 1/3 | origin = (x = 286.5, y = 426), size = (width = 83.5, height = 84) |
8 | 2/0 | origin = (x = 25, y = 530), size = (width = 325, height = 150) |
9 | 2/1 | origin = (x = 25, y = 695), size = (width = 325, height = 150) |
10 | 2/2 | origin = (x = 25, y = 860), size = (width = 325, height = 150) |
。
根据底边(y+height)降序排序的索引 。
。
index | 标号(muiid) | rect |
---|---|---|
0 | 2/2 | origin = (x = 25, y = 860), size = (width = 325, height = 150) |
1 | 2/1 | origin = (x = 25, y = 695), size = (width = 325, height = 150) |
2 | 2/0 | origin = (x = 25, y = 530), size = (width = 325, height = 150) |
3 | 1/0 | origin = (x = 5, y = 360), size = (width = 177.5, height = 150) |
4 | 1/2 | origin = (x = 192.5, y = 360), size = (width = 177.5, height = 56) |
5 | 1/3 | origin = (x = 286.5, y = 426), size = (width = 83.5, height = 84) |
6 | 1/1 | origin = (x = 192.5, y = 426), size = (width = 84, height = 84) |
7 | 0/2 | origin = (x = 25, y = 180), size = (width = 156, height = 150) |
8 | 0/3 | origin = (x = 194, y = 180), size = (width = 156, height = 150 |
9 | 0/0 | origin = (x = 25, y = 15), size = (width = 156, height = 150 |
10 | 0/1 | origin = (x = 194, y = 15), size = (width = 156, height = 150) |
。
查找 。
前两步是在执行完reload,在视图还没有生成的时候就开始做了,而接下来的步骤在要生成视图(初始化或滚动的时候)才会去做.
我们设定了buffer为上下各20,滚动超过20个像素后才会指定查找视图并显示的动作。举个例子,如下图,红圈是应该显示的区域.
如上图所示,现在已知的是红圈顶边y是242,底边y是949,加上缓冲区buffer,应该是找222 - 969 之间的view。我们要做的是,找到底边y小于969的model和顶边y大于222的model,取交集,就是我们要显示的view.
采用的方法为二分查找,在根据顶边升序排序的索引中找949,找到的index为0(muiid为2/2),我们使用一个set,把根据顶边排序中index >= 0 的元素先放在这里。获取的set中包含的muiid为 0/0,0/1,0/2,0/3,1/0,1/1,1/2,1/3,2/0,2/1,2/2.
根据底边排序的索引中找222,找到的index为2,我们把index >= 2的元素放在另一个set,获取的set中包含的muiid为0/2,0/3,1/0,1/1,1/2,1/3,2/0,2/1,2/2 。
两个set取交集,得到的就是我们的resultset,这里面都是我们要显示view的model,它们的muiid是0/2,0/3,1/0,1/1,1/2,1/3,2/0,2/1,2/2.
回收、复用、生成 。
我们知道了应该显示哪些view,但是我们之后做的第一步是把不需要显示的view加入到复用池中。lazyscroll可以取到当前显示了的view,拿当前显示的view的muiid和将要显示view的model的muiid做对比,可以知道当前显示的view哪些应该被回收.
lazyscrollview中有一个dictionary,key是reuseidentifier,value是对应reuseidentifier被回收的view,当lazyscrollview得知这个view不该再出现了,会把view放在这里,并且把这个view hidden掉.
然后,用lazyscrollview会去调用datasource.
1
|
- (uiview *)scrollview:(tmmuilazyscrollview *)scrollview itembymuiid:(nsstring *)muiid;
|
复用还是不复用,是由datasource决定的。如果要复用,需要datasource方法内调用,即:
1
|
- (uiview *)dequeuereusableitemwithidentifier:(nsstring *)identifier
|
获取复用的view,这个方法取出来的view就是在上一段所说的dictionary中拿的。 最后我们看一下lazyscrollview的使用流程:找到所有view将要显示的位置 – 排序 – 查找应该显示的view – 回收 – 创建/复用.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.
原文链接:http://blog.csdn.net/xiangzhihong8/article/details/53898810 。
最后此篇关于详解iOS 滚动视图的复用问题解决方案的文章就讲到这里了,如果你想了解更多关于详解iOS 滚动视图的复用问题解决方案的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
如果附加了 'not-scroll' 类,我希望我的 body 不滚动,否则它应该正常工作。 我已经搜索这个问题两天了,但找不到任何适合我的解决方案。 我想要的是向 body 添加一个 class,并
我发现似乎是 iOS Safari 中的错误(我正在 iOS 8 上进行测试)。当绝对定位的 iFrame 漂浮在一段可滚动内容上方时,滚动 iFrame 也会滚动下面的内容。以下 HTML (ava
我有以下代码来显示一系列投资组合图片,这些图片以 SVG 格式存储在滚动 div 中: 在 Safari 中滚动使用两根手指或鼠标滚轮当光标位于 SVG 之一上时不起作用。 该页
我想用 javascript 做的是: 一旦你向下滚动页面,将#sidebar-box-fixed 的位置从 position: relative; 更改为定位:固定;。改回position:rela
我对 Elasticsearch 的滚动功能有点困惑。在 elasticsearch 中,每当用户在结果集上滚动时,是否可以每次调用搜索 API?来自文档 "search_type" => "scan
我试图做到这一点,以便当我向上或向下滚动页面时,它会运行不同的相应功能。我发现了一个类似的问题here但我已经尝试了他们的答案并且没有运气。 注意:此页面没有正常显示的滚动条。没有地方可以滚动。 bo
(C语言,GTK库) 在我的表单上,我有一个 GtkDrawingArea 小部件,我在上面使用 Cairo 绘制 GdkPixbufs(从文件加载)。我想要完成的是能够在窗口大小保持固定的情况下使用
最近我一直在尝试创建一个拉到(刷新,加载更多)swiftUI ScrollView !!,灵感来自 https://cocoapods.org/pods/SwiftPullToRefresh 我正在努
我正在开发一个应用程序,其中有两个带有可放置区域的列表和一个带有可拖动项目的侧面菜单。 当我滚动屏幕时,项目的位置困惑。 我试图在谷歌上寻找一些东西,最后得到了这个问题:jQuery draggabl
我在 UIWebView 中加载了一个 HTML 表单,而我的 UIWebView 恰好从 View 的中间开始并扩展。我必须锁定此 webView 不滚动并将其放在 ScrollView 之上以允许
如何在每个元素而不是整个元素上应用淡入淡出(与其高度相比)? HTML: CSS: * { padding: 0; margin: 0; box-sizing: border
我想使用带有垂直轴的 PageView 并使用鼠标滚动在页面之间移动,但是当我使用鼠标滚动时页面不滚动...仅页面单击并向上/向下滑动时滚动。 有什么办法吗? 我想保留属性 pageSnapping:
我制作这个程序是为了好玩,但我被卡住了,因为程序在屏幕外运行。如何在不完全更改代码的情况下实现滚动条。 public static void main(String args[]) throws IO
我想使用带有垂直轴的 PageView 并使用鼠标滚动在页面之间移动,但是当我使用鼠标滚动时页面不滚动...仅页面单击并向上/向下滑动时滚动。 有什么办法吗? 我想保留属性 pageSnapping:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
使用 jquery 技术从 css-tricks.com 获得滚动/跟随侧边栏,如果您不知道我在说什么,这里是代码: $(function() { var $sidebar = $
我是 jQuery Mobile 新手。我需要向我的应用程序添加 Facebook 滑动面板功能。 我经历了 sliding menu panel ,它工作正常,但我在菜单面板中的内容超出了窗口大小,
有没有办法在 js 或 jQuery 或任何其他工具中检测 ctrl + 滚动。我正在尝试执行一些动态布局代码,我需要检测不同分辨率下的屏幕宽度,我通过使用 setTimeout() 的计时器实现了这
我有一部分html代码:
我想控制 RichTextBox 滚动,但在控件中找不到任何方法来执行此操作。 这样做的原因是我希望当鼠标光标位于 RichTextBox 控件上时鼠标滚轮滚动有效(它没有事件焦点:鼠标滚轮事件由表单
我是一名优秀的程序员,十分优秀!