列表控件实现原理解析
2014-09-30 16:03
190 查看
离上一次写文章已经有好几个月了,工作后比较忙碌,没有多少时间来写,想想几个月前还在学校每天睡到自然醒,是多么幸福的事,还在学校里的少年,珍惜吧! 今天是国庆放假前夕,好多同事提前请假回家了,旁边的格位都空荡荡,按部分老同事的话说:“这好比过年前的景象“。没心情写代码,没心情改BUG,过来写篇文章也是好的。
闲聊了几句,进入正题。列表控件无论是在PC客户端程序、网页还是android APP都经常用到,其重要性就不在此强调了。我们先来说一下列表控件的构成:
上图是360云盘的截图,从图中的标注可以看出,列表控件的主要由3部分组成:
1、列表头,描述每一列的含义
2、列表项容器,用于放置列表项的容器。列表中的一行表示列表项,列表项可以认为是一个单独的控件,由基础控件组成,如下图的列表项由一个icon控件和五个text控件组成(文件名、位置、日期、类型、大小)
3、滚动条,非常重要的组成部分,滚动条位置的变化导致列表项容器中内容的变化。
说完构成,再来说说列表控件的工作原理。
假设有50条数据,每一条数据被展示在一个列表项中,列表项的30像素,那么定义数据的总高度为 totalHeight = itemNum * itemHeight = 50 * 30 = 1500。又假设列表项容器(简称为客户区)高度为300,很显然最多能容纳10个列表项控件,即同时只能显示10条数据。初始化的时候,我们只能看到前面10条数据,怎么才能把后面40条数据显示出来呢?答案很简单,只需要拖动滚动条即可,当然拖动滚动条只是表象,起作用的原理是:滚动条的位置发生了变化,而根据滚动条所在的位置计算得出的当前可显示的数据范围发生了变化。如下表:
滚动条位置 数据范围
pos1 [1,,10]
pos2 [11, 20]
pos3 [21, 30]
......
简单解释一下上表:滚动条在位置pos1时,计算出可显示的数据为第1条到第10条,那么我们将从数据源(一般都成为DataSource)中取出这10条数据,并显示在客户区内;同理,当我们拖动滚动条至pos2时,我们将从DataSource中取出第11条至第20条数据显示在界面上。也就是说,界面上的10个列表项控件始终存在,改变的只是显示在列表项中的数据,只是数据切换到控件上的速度太快,人眼感觉不到而已。那么问题又来了,怎么根据滚动条的位置来计算当前显示的数据范围?
先来看看滚动条的构成:滚动条控件 = 滚动槽 + 中间那个可以拖动的按钮(没有专业的名词,暂且叫滚动条按钮),我们这里只考虑垂直方向的滚动条,水平方向的滚动条略过。然后梳理一下几个高度概念:
数据的总高度之前已经介绍过, totalHeight = itemNum * itemHeight
客户区高度,它是不可变的(这里不考虑用户对窗口的拉伸,特殊情况后面在讨论),假设为clientHeight
滚动条的物理高度(可以理解为人眼实际看到的高度),其实就是滚动槽的高度,假设为trackHeight
滚动条的逻辑高度,它的值等于totalHeight
定义滚动条的逻辑高度与物理高度为 rate = totalHeight / trackHeight,简单理解为一个物理像素相当于rate个逻辑像素
好吧,本质原理其实就是将滚动条所在位置的物理高度,换算为逻辑高度,然后根据逻辑高度计算可见的数据范围。
有了上面几个概念,再来说“如何按滚动条的位置来取数据显示到界面”就简单了,举个例子:
还是上面50条数据,则已知逻辑高度为1500,假设滚动条在界面上的物理高度为300(通常的实际情况是,滚动条的高度 = 客户区的高度 + 列表头的高度,这里为了方便计算,除去了列表头的高度,因此高度刚好等于客户区的高度)。计算可得:
rate = 1500 / 300 = 5
那么当滚动条的位置在最顶上时,即所在位置的物理高度为0时,那么显示的逻辑范围为[0,0 + 300],不难计算数据1到10在这个范围内,因此显示范围为[1, 10];
如果滚动条被拖动至物理高度为120的位置,那么显示的逻辑范围为[120 * 5, 120 * 5 + 300],那么开始下标为startIndex = 120 * 5 / 30 = 20, 结束下标endIndex = (120 * 50 + 300) / 30 = 30,这里注意一下,第20条数据位于的逻辑高度为[570, 600],因此第20条数据其实无法显示出来,因此正确的显示范围为[21, 30] 。
一句话总结一下列表控件的运行原理:滚动条所在位置的物理高度,换算为逻辑高度,根据逻辑高度计算当前数据的显示范围,然后将范围内的数据显示在客户区内。因此我们平常拖动滚动条或是鼠标滚动,客户区内容能够发生变化,其实就是上面原理作用的结果。有时间再跟大家说一下如何应对窗口的拉伸、插入新的数据、删除数据以及列表控件的代码实现。
闲聊了几句,进入正题。列表控件无论是在PC客户端程序、网页还是android APP都经常用到,其重要性就不在此强调了。我们先来说一下列表控件的构成:
上图是360云盘的截图,从图中的标注可以看出,列表控件的主要由3部分组成:
1、列表头,描述每一列的含义
2、列表项容器,用于放置列表项的容器。列表中的一行表示列表项,列表项可以认为是一个单独的控件,由基础控件组成,如下图的列表项由一个icon控件和五个text控件组成(文件名、位置、日期、类型、大小)
3、滚动条,非常重要的组成部分,滚动条位置的变化导致列表项容器中内容的变化。
说完构成,再来说说列表控件的工作原理。
假设有50条数据,每一条数据被展示在一个列表项中,列表项的30像素,那么定义数据的总高度为 totalHeight = itemNum * itemHeight = 50 * 30 = 1500。又假设列表项容器(简称为客户区)高度为300,很显然最多能容纳10个列表项控件,即同时只能显示10条数据。初始化的时候,我们只能看到前面10条数据,怎么才能把后面40条数据显示出来呢?答案很简单,只需要拖动滚动条即可,当然拖动滚动条只是表象,起作用的原理是:滚动条的位置发生了变化,而根据滚动条所在的位置计算得出的当前可显示的数据范围发生了变化。如下表:
滚动条位置 数据范围
pos1 [1,,10]
pos2 [11, 20]
pos3 [21, 30]
......
简单解释一下上表:滚动条在位置pos1时,计算出可显示的数据为第1条到第10条,那么我们将从数据源(一般都成为DataSource)中取出这10条数据,并显示在客户区内;同理,当我们拖动滚动条至pos2时,我们将从DataSource中取出第11条至第20条数据显示在界面上。也就是说,界面上的10个列表项控件始终存在,改变的只是显示在列表项中的数据,只是数据切换到控件上的速度太快,人眼感觉不到而已。那么问题又来了,怎么根据滚动条的位置来计算当前显示的数据范围?
先来看看滚动条的构成:滚动条控件 = 滚动槽 + 中间那个可以拖动的按钮(没有专业的名词,暂且叫滚动条按钮),我们这里只考虑垂直方向的滚动条,水平方向的滚动条略过。然后梳理一下几个高度概念:
数据的总高度之前已经介绍过, totalHeight = itemNum * itemHeight
客户区高度,它是不可变的(这里不考虑用户对窗口的拉伸,特殊情况后面在讨论),假设为clientHeight
滚动条的物理高度(可以理解为人眼实际看到的高度),其实就是滚动槽的高度,假设为trackHeight
滚动条的逻辑高度,它的值等于totalHeight
定义滚动条的逻辑高度与物理高度为 rate = totalHeight / trackHeight,简单理解为一个物理像素相当于rate个逻辑像素
好吧,本质原理其实就是将滚动条所在位置的物理高度,换算为逻辑高度,然后根据逻辑高度计算可见的数据范围。
有了上面几个概念,再来说“如何按滚动条的位置来取数据显示到界面”就简单了,举个例子:
还是上面50条数据,则已知逻辑高度为1500,假设滚动条在界面上的物理高度为300(通常的实际情况是,滚动条的高度 = 客户区的高度 + 列表头的高度,这里为了方便计算,除去了列表头的高度,因此高度刚好等于客户区的高度)。计算可得:
rate = 1500 / 300 = 5
那么当滚动条的位置在最顶上时,即所在位置的物理高度为0时,那么显示的逻辑范围为[0,0 + 300],不难计算数据1到10在这个范围内,因此显示范围为[1, 10];
如果滚动条被拖动至物理高度为120的位置,那么显示的逻辑范围为[120 * 5, 120 * 5 + 300],那么开始下标为startIndex = 120 * 5 / 30 = 20, 结束下标endIndex = (120 * 50 + 300) / 30 = 30,这里注意一下,第20条数据位于的逻辑高度为[570, 600],因此第20条数据其实无法显示出来,因此正确的显示范围为[21, 30] 。
一句话总结一下列表控件的运行原理:滚动条所在位置的物理高度,换算为逻辑高度,根据逻辑高度计算当前数据的显示范围,然后将范围内的数据显示在客户区内。因此我们平常拖动滚动条或是鼠标滚动,客户区内容能够发生变化,其实就是上面原理作用的结果。有时间再跟大家说一下如何应对窗口的拉伸、插入新的数据、删除数据以及列表控件的代码实现。
相关文章推荐
- 第14章8节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-获取控件列表并建立控件树
- 老李推荐:第14章8节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-获取控件列表并建立控件树 5
- 老李推荐:第14章8节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-获取控件列表并建立控件树 1
- 下拉刷新、上拉加载更多控件实现原理及解析(一)
- 第14章8节《MonkeyRunner源代码剖析》 HierarchyViewer实现原理-获取控件列表并建立控件树
- 老李推荐:第14章8节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-获取控件列表并建立控件树 3
- 老李推荐:第14章8节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-获取控件列表并建立控件树 3
- 下拉刷新、上拉加载更多控件实现原理及解析(一)
- OPhone自定义UI控件的实现原理解析
- 老李推荐:第14章8节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-获取控件列表并建立控件树 4
- 老李推荐:第14章8节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-获取控件列表并建立控件树 1
- 老李推荐:第14章8节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-获取控件列表并建立控件树 2
- 下拉刷新、上拉加载更多控件实现原理及解析
- 下拉刷新、上拉加载更多控件实现原理及解析(二)
- 老李推荐:第14章8节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-获取控件列表并建立控件树 6
- 老李推荐:第14章8节《MonkeyRunner源码剖析》 HierarchyViewer实现原理-获取控件列表并建立控件树 2
- JavaScript解析Json实现动态修改多级下拉选择列表控件Select
- 下拉刷新、上拉加载更多控件实现原理及解析(二)
- OPhone自定义UI控件的实现原理解析(浮动导航栏)
- 数据库水平切分的实现原理解析-分库,分表,主从,集群,负载均衡器