Android响应式方案
响应式的核心是拉通多终端的适配规则,开发一套界面,一个APP兼容多尺寸终端设备的显示,能够根据用户的行为以及设备的环境(屏幕尺寸、屏幕方向、是否分屏等)进行相应的页面布局以及容器尺寸的调整,为用户提供更加舒适的界面和更好的用户体验。
1 响应式SDK
App的每个页面支持响应式,开发成本是很高的。
响应式SDK,就是为了解决App在不同尺寸设备下的适配问题,把设备的屏幕信息、容器布局规则(列数、尺寸)、业务数据二次加工等行为进行统一管理,以适应新的屏幕尺寸。
2 加载流程设计
通用的页面加载流程,通常都是从数据返回开始,数据解析完成后,进行页面布局渲染以及容器布局渲染。响应式在通用加载流程的基础上,加入了响应式状态变化通知、响应式数据剪裁、响应式页面布局、响应式容器布局等流程。
具体加载的流程分为两种情况:
- 用户请求数据
- 屏幕尺寸发生变化
3 架构设计
优酷各个业务开发团队,使用了统一的业务架构,我们在统一架构的基础上进行响应式适配,提供了响应式SDK,拉通各个业务方不同页面的适配规则,确保了适配效果的一致性,同时提供了基础的响应式控件,降低业务方的接入成本,那么响应式架构具体是怎么实现的呢?
从结构上看,响应式由优酷统一架构、响应式SDK、响应式页面布局、响应式容器布局四部分相互配合完成。在这些基础上支撑了首页、频道页、播放页、会员页、搜索、个人中心等众多的业务场景。
优酷统一架构和响应式SDK,提供响应式架构能力。
响应式页面布局、响应式容器布局,提供响应式参考实现。
4 数据二次加工
响应式并不是简单的将现有Phone端的业务数据,投放到Pad、折叠屏上,单纯的进行UI页面适配。想要在不同尺寸设备上都能获得良好的适配效果,需要对Phone端的业务数据二次加工,进行数据过滤、数据映射、数据合并、数据补全等操作,才能更好的适配Pad和折叠屏。
响应式SDK只是负责把数据二次加工的协议规则定下来,具体的数据二次加工逻辑需要业务方自己实现。优酷的统一架构提供了数据切面的能力,在切面上增加数据二次处理的逻辑,实现了统一的数据处理。
数据过滤
大尺寸设备上,总会遇到一些复杂的,适配不了的,也不重要的组件,这部分组件可以根据具体情况过滤处理,例如:下图中的weex组件,在Pad上直接过滤掉,不显示。
数据映射
存在一些带交互的复杂组件或者Pad上适配效果较差的组件,可以直接映射成其他已适配的组件。例如:下图中的带视频预览的预约组件映射成普通的预约组件。
数据合并
相邻的两个组件,其中有一个组件无法很好的适配大尺寸Pad,可以尝试将其数据合并到其他组件内。
例如:下图中第1个组件宽度铺满页面宽度,在大尺寸上无法适配,第2个组件通过修改列数、尺寸就可以适配。Pad竖屏下,将第一个组件插入到第二个组件的首位,进行数据合并,按照第二个组件的进行适配,显示为3列2行,达到很好的适配效果。
数据补全
在横竖屏切换过程中,部分组件会遇到组件的数量,无法铺满屏幕的宽度,导致出现留白的问题。
例如:把手机上的6条数据,直接投放到Pad横屏下,就会出现下图的留白问题:
为了解决这一类数据缺失的问题,我们选择的解法是服务端多下发一部分业务数据,客户端根据具体的屏幕尺寸,动态调整显示的个数,确保显示效果。
例如:下图中手机上显示2列3行,共6条数据,到了Pad竖屏上显示3列2行,共6条数据,到了Pad横屏上会补全2条数据,显示4列2行,共8条数据。
5 页面响应式
响应式状态
响应式状态是页面响应式最基础也是最重要的一个能力,像横竖屏切换、分屏模式、折叠屏折叠打开,都会导致页面的宽高发生变化,产生不同的响应式状态,页面内的内容会进行重新布局以及组件尺寸调整,以适应页面尺寸的变化,铺满屏幕,达到更好的显示效果。
横竖屏切换:
分屏模式:
折叠屏:
响应式状态管理
响应式状态与Activity页面的生命周期保持一致,不同页面响应式状态可能不一致。响应式SDK提供了ResponsiveActivity、ResponsiveFragment两个基类,ResponsiveActivity统一封装了响应式的状态变化。当屏幕尺寸发生改变时,ResponsiveActivity和ResponsiveFragment会回调onResponsiveLayout方法,业务方接到onResponsiveLayout的通知,主动遍历当前页面内的所有容器,根据响应式状态,动态修改容器的布局、布局列数、尺寸等,重新渲染当前页面。
由于优酷使用了统一框架,根据响应式状态动态修改页面内所有容器的逻辑,统一在框架内部处理,避免了业务方的修改,降低了接入成本。
/**
*响应式状态回调
*
* @param newConfig 配置信息
* @param responsiveLayoutState 当前响应式状态
* @param responsiveLayoutStateChanged响应式状态是否已发生改变
*/
protectedvoidonResponsiveLayout(ConfigurationnewConfig,intresponsiveLayoutState,booleanresponsiveLayoutStateChanged) {
}
获取响应式状态
响应式状态的定义,需要有一个具体计算的规则,在所有尺寸的设备上都按照统一的规则进行状态区分,那么不同的响应式状态是如何区分的呢?
首先定义标准手机屏幕的物理宽度为400dp(经过大量手机设备调试采样之后获得的手机标准物理尺寸经验值),那么响应式状态的变化,由两个比例阈值决定,一个是页面物理宽度与标准物理宽度的比例阈值1.67倍(物理宽度 = 像素宽度÷屏幕密度),另一个是页面高度与页面宽度的比例阈值1.25倍。那么这两个比例阈值是如何得来的呢?
(1)1.67倍是怎么来的呢?
在播放页的适配过程中,需要适配左右分栏的显示,我们认为左侧播放器的宽度是标准物理宽度,那么整个页面的宽度就是标准物理宽度的1.67倍,这样左侧播放器有足够的空间保障视频播放的体验,右侧的也有足够的空间保障评论的显示效果。
(2)1.25倍是怎么来的呢?
上图列举了竖屏华为Pad上,页面高度是页面宽度的1.6倍,播放器下方的视频内容操作区,显示的视频内容是足够多的。如果页面高度小于页面宽度的1.25倍,就会挤压视频内容操作区的高度,导致显示出来的视频内容过少,影响用户体验。
当页面物理宽度大于标准物理宽度的1.67倍,同时页面高度小于等于页面宽度的1.25倍,即为大屏状态,其他情况则为小屏状态。
不同的响应式状态
目前支持了小屏布局和大屏布局两种状态。
(1)小屏布局状态
折叠屏折叠、折叠屏分屏、Pad竖屏:
(2)大屏布局状态
折叠屏打开、Pad横屏:
6 容器响应式
容器响应式,主要解决在页面尺寸发生变化时,动态调整容器布局的列数以及坑位的尺寸,优酷统一架构提供了常用的响应式容器布局:轮播布局、网格布局、横划布局、瀑布流布局。业务方可以快速实现响应式的效果。
容器适配列数、尺寸的效果
列数适配
同一个容器,在不同的尺寸页面下,会根据页面的物理宽度动态适配,显示为不同的列数。
网络布局、横划布局、瀑布流布局都采用这一套列数适配的规则:
响应式适配后的列数 = 当前屏幕宽度÷(标准屏幕宽度÷标准屏幕宽度下的组件列数 )
响应式适配后的列数,并不能解决Pad横屏上部分组件列数过多,显示过密的问题,为了解决这类问题,提供了列数二次适配的能力。
如下图所示,左侧是直接根据规则算出来的Pad横屏下的列数8列,过于密集,显示效果不好,右侧是列数二次调整后,显示为6列。
适配效果:
控件尺寸适配
由于不同屏幕尺寸下,容器内部会动态调整显示不同的列数,导致控件的尺寸也会发生变化,那么如何适配控件尺寸的动态变化呢,响应式基础控件能够很好的解决这一类问题。
响应式基础控件,内部封装了响应式容器尺寸的适配规则,通过ratioType来定义不同适配规则下控件宽高的计算逻辑,业务方只需要修改最外层的布局控件,通过设置ratioType就可以快速搞定宽高适配,降低业务方的适配成本。
提供了ResponsiveConstraintLayout、ResponsiveFrameLayout、ResponsiveLinearLayout、ResponsiveRelativeLayout、ResponsiveRecyclerView等基础响应式容器。
ratioType的宽度计算规则示例(页面左右边距和横间距不变):
响应式控件宽度 = (当前页面的宽度 - 左右边距 - 控件之间的间距总和)÷响应式适配后的列数
总结
随着折叠屏技术的进一步发展,折叠屏手机会越来越普及,越来越多的App需要适配到折叠屏手机上,响应式可以很好的解决折叠屏的适配问题。希望未来更多的APP能够适配响应式,做到一套代码,运行到不同尺寸的设备上,节约开发成本,提升开发效能,为不同尺寸的设备带来与手机版本一致的用户体验。