滚动界面一般是由可滚动区域和不可滚动区域组成,比较常见的是标题栏、导航栏部分不会随着内容的滚动而变换位置,滚动区域则可以上下进行滚动。如下图
为了实现这种布局在使用HTML技术进行移动应用开发过程中,由于手机浏览器引擎能力缺陷问题,
注:比较有代表性的问题有 1)、overflow的scroll属性不能友好的支持元素内部内容在元素内部滚动 2)、position的fixed属性不能保证DOM元素在屏幕上固定
曾有过多种解决方案。
即通过把窗口划分为头部、底部、内容三个部分,三个部分都固定大小,且组合后覆盖整个窗口。然后再在内容区域插入需要滚动的超过屏幕大小的内容。为了使在内容区域插入的内容可以随着用户手指的操作进行滚动,需要把内容区域overflow-y样式设定为hidden,然后通过JS截获用户触摸屏幕的touchstart、touchend、touchmove事件,通过计算用户手指移动,通过变更滚动内容的位置(transform:translateY)实现界面的滚动效果。如下图所示
这种方式可以使用JS实现,因此其可以运行在混合式移动应用中,也可以使用在移动网站、微信网站中,具有良好的通配性(scroll 为了提高滚动效率,没有对滚动做js处理,只是监听到底事件,目前只支持下拉刷新)。 这种方式完全靠JS进行实现,iScroll是比较代表性的实现方案。但这种方案由于全部使用JS实现,效率比较低下,尤其在早期android中,无法满足用户体验要求。其次由于滚动区域是在DOM元素内部滚动,因此在把界面代码做为网站使用时,与有些浏览器的体验效果产生冲突,例如iPhone设备中,网页滚动会把地址栏变小,使用这种方式实现的话,则不会产生此效果,减少了用户可视范围。
为了避免上述问题,提高移动应用体验,AppCan首先提出了窗口叠加方案,并在众多项目中进行了实践。即主体布局与第一种方案相同,但是滚动内容部分不再放入到滚动容器中,而是在滚动容器上覆盖一个与容器同样大小的独立浏览器窗口,需要滚动的内容将会在这个独立的浏览器窗口中进行展示。如下图
这种方式将滚动操作交由系统WEBVIEW进行实现,保证了滚动的体验效果,但是需要把滚动内容部分变为一个独立的网页,即一个界面需要两个独立网页来组成。
随着移动终端系统的不断改进,各种缺陷不断被弥补,之前不能够友好支持的能力也逐渐得到改善。AppCan提出了新的移动布局方案,即内容区域作为界面的主体,他的长度可以超过屏幕容纳范围,这时通过浏览器本身的能力即可支持用户友好的上下滚动界面,需要固定在屏幕上的DOM元素例如标题、导航等,通过position的fixed属性固定显示在屏幕的指定区域。如下图
这种方式中,滚动是通过浏览器默认能力进行实现的,滚动体验效果好,且所有内容都在一个页面中,不需要独立构建内容页。由于只需要使用一个WEBVIEW进行展示,同时也减少了内存占用。这种方案在作为网站通过浏览器访问时,不会与浏览器冲突,体验会更好。例如 这种方案中,由于内容区域被顶部栏和底部栏覆盖了部分区域,为了保证内容区域所有元素在滚动时都可被显示,需要在内容区域加入上下边界余量。
AppCan IDE提供了UI设计器帮助我们快速构建滚动区域框架。通过APPCAN IDE新建一个项目,然后打开index.m文件,可以看到这是AppCan IDE默认提供的标准页面设计,他是一个经典的滚动框架布局。如下图
上图可以看出index.m定义的滚动界面是由一个页面元素Page做为基础,里面包含了标题和滚动区域两个布局组件。我们也可以通过设计器自行建立一个滚动界面。
在需要添加新界面的目录上单机鼠标右键,选择新建->AppCan页面(可拖拽)。
在文件名中输入scroll。点击完成,建立新界面。
###### 2.4、 在Page控件中,添加一个标题控件
注:向一个控件中添加子控件时,先要使其获取焦点
###### 2.5、 在Page控件中,添加一个滚动容器控件
###### 2.6、根据标题控件高度调整滚动容器上部余量
注:可以单击一个控件,然后通过上部的提示信息获取控件宽度和高度
###### 2.7、 保存界面设计并导出全部
注:通过不同的导出方式可以对导出的内容进行部分更新
###### 2.8.设计完成
###### 3.1、 代码结构
通过设计器生成的代码包含三个文件 scroll.html-包含布局框架的HTML代码 scroll.css-包含布局框架中控件的个性化样式配置 scroll.js-包含布局框架中控件的操作交互代码
###### 3.2、 布局框架代码分析
在IDE中打开scroll.html文件,可以看到如下代码(为了阅读方便对部分代码进行了显示折叠)
上述代码中,可以看到我们在设计器中添加的页面及页面中标题和滚动区域控件。滚动区域控件中, ###### 3.3、 布局框架样式分析 HTML中,通过为元素设定data-control属性定义了控件的类别。并通过在ui-base.css文件中为不同控件类别定义了基础属性。如下述代码
[data-control=”PAGE”]定义了页面的最小高度为屏幕的总高度,保证界面的显示完整性。
[data-control=”HEADER”]定义了经典标题栏控件的位置是相对于物理屏幕Y轴坐标0位置,其层叠索引z-index为1000,使其覆盖于其他索引小于1000的控件之上。
在设计界面时我们为滚动区域定义了42px的上部余量,这是一个界面自定义属性,所有界面自定义属性都会放置到界面所对应的css文件中。我们打开scroll.css可以看到为滚动控件设定的样式属性。
上述代码中通过控件的ID构建CSS样式类对象,对象中定义了padding属性。其中上内边界为2.63em。我们可以注意到,在设计器里面我们输入的数值是42px,为什么不同呢?
这是由于目前移动终端设备屏幕分辨率、物理屏幕大小有很多的型号。为了保证开发人员构建的移动界面在任何分辨率下都可以保证用户有最好的体验,我们开发时需要对宽、高、位置等受分辨率影响用户体验的元素属性进行相对设定。因此我们在设计器里面输入了上内边界42px,设计器字体大小为16px,因此换算后即为2.625em约等于2.63em。当通过这种方式构建的界面到更高分辨率更高精度的屏幕上时,根据其手机的基础字体大小就可以保证界面有相同体验。 ###### 3.4、滚动界面交互事件分析 滚动界面直接需要面对的最常用事件包含屏幕滚动到末尾和屏幕滚动到最上后继续拖拽的事件。我们常见的是当界面滚动到末尾时自动加载新的数据到界面中和当界面滚动到最开始,然后继续向下拖动时出发数据更新的场景。
滚动控件已经默认进行了封装。我们可以打开scroll.js查看默认代码
上述代码中,我们可以看到向下滚动和滚动到屏幕底部所触发的各种事件。
“draging”事件是当界面处于最上位置时,继续向下拖拽时,随着拖拽的距离不断触发的事件
“release”事件是当界面处于最上位置时,继续向下拖拽,在不超过最大拖拽距离30%时候释放所触发的事件
“dragToReload”事件是当界面处于最上位置时,继续向下拖拽,当拖拽的距离超过最大拖拽距离30%临界点时触发的事件,只会出发一次。
“releaseToReload”事件适当界面处于最上位置时,继续向下拖拽,当拖拽的距离超过最大拖拽距离30%临界点后释放时出发的事件,此事件产生后,默认代码会触发一个reload事件发送给滚动容器控件,用于触发数据更新等操作。需注意,产生“releaseToReload”此事件后,滚动容器将停留在reloading状态直到调用reset接口进行复位。
“onReloading”事件是当滚动容器在reloading状态时,重新拖拽产生的事件
下图是各个事件触发的时间点
“scrollbottom”事件是当滚动容器内容超过屏幕显示时,内容向上滚动到底部时触发的事件。此事件产生后,默认代码会触发一个more事件发送给滚动容器控件,用于触发数据更新等操作。
对于默认代码中产生的“reload”和“more”事件,我们可以通过如下代码进行监听,并加入我们自己的事件处理代码。例如
若仅仅需要拖拽弹动的效果而不需要显示弹动区域的内容和处理相关事件,那么只需要调用hide函数即可。如下图
若希望人工进入“releaseToReload”状态,则需要调用reload函数。reload函数的效果与人为拖拽界面超过30%后释放的效果相同。代码如下图