干货 | Flutter控件CustomScrollView原理解析及应用实践

作者简介

 

popeye,携程软件技术专家,关注移动端跨端技术,致力于快速,高性能地支撑业务开发。

说起移动端跨平台解决方案,Flutter无疑是最近被谈到最多的话题。相对于React Native这样的前端技术栈,Flutter更贴近于客户端的技术栈特性,所以迅速获得大批原移动端开发的热烈拥护,再加上其优秀的渲染性能和友好的开发模式,目前已经在业内被广泛使用。

携程酒店研发从去年底开始对Flutter进行可行性调研,在今年年初陆续完成了酒店详情页和酒店列表页的转Flutter工作,通过这项工作,实现了客户端技术栈的统一,大大提高了研发效率和双端一致性。在Flutter开发的过程中,对CustomScrollView的使用是比较多的,这也是我们开发过程中比较重要和复杂的控件。    

 

图1  CustomScrollView可承载的子布局类型

 

CustomScrollView是Flutter的SDK提供的实现长列表的控件。它像一个强大的粘合剂,如图1所示在此控件中我们可以将各种不同的布局,比如列表,网格,瀑布流,吸顶组件等,在其里面组合,实现较为复杂的页面。以往在Native的开发中,官方组件没有提供如此强大的组合能力,我们在Native中实现列表中组合不同布局,或者是通过index映射布局类型这种异构的方式,或者需要自己去自定义一个能够组合不同布局的控件,都没有CustomScrollView方便。

 

图2  酒店详情页使用的主要sliver类型

 

图2是携程酒店详情页主要模块所使用到的布局类型。如上文提到,系统提供的布局方式还是很强大的,基本能够满足我们这个相对复杂页面大多数的布局要求,当然有些特殊的模块,需要去做一些定制,比如通过定制“paintOrigin”实现的日历模块的特殊吸顶交互等。

对于这个较复杂且使用广泛的组件的内部实现原理有较深入的了解,对于我们的应用以及后续的性能优化都有较大意义。因此本文将对其实现原理做一定的剖析,并就其在实际工作中的应用实践给出具体例子。

 

 一、概述

1.1 Flutter渲染流程简述

图3  Flutter渲染流程

 

FlutterUI绘制的驱动主要可以简述如图3所示。可以看到,Flutter的Framewrok在启动初始化后主要构建了四颗树Widget、Element、RenderObject和Layer。然后在系统Vsync的驱动下,通过它们的改变生成出绘制每一帧画面的数据,然后显示到屏幕上。

其中的Widget树是平常接触最多的一颗树,它类似一颗配置数据树,配置页面的样子。而RenderObject树则是一颗真正的实现生成绘制内容树,完成各个控件的大小计算,布局,以及绘制数据,它的数据来源就是前面的Widget树。


中间的Element树更像是一个媒介,因为Flutter借鉴了当今比较流行的React的思想,它并不希望我们还是像以前在Native的时候直接去操作RenderObject,而是希望我们在它的框架下面只配置我们想要什么,以及状态怎么改变,而最终的复杂的位置计算和如何绘制交给它解决。因此中间的Element树因此就应运而生,它会负责根据Widget树去生成和改变RenderObject树,当然这个过程中会做一定的Diff策略,从而尽量减少RenderObject树的变化,因为RenderObject树的变化相对来说是比较大的。

最终RenderObject树会生成Layer树,Layer树是Flutter engine所需要的数据格式,Flutter engine会利用这颗树进行相应渲染,并最终绘制在我们宿主平台提供给Engine的画布上。

 

图4  CustomScrollView的三层结构

 

CustomScrollView作为Flutter提供的控件,其内部结构肯定也是上述这样,图4给出了其三层(Widget,Element,RenderObject)对应的结构图。

首先看一下其在Widget这层的主要构成。总的来说由两部分构成:第一部分是Srollable,这层主要是接受用户手势同时根据配置参数,决定相应的滑动位置;第二部分是真正要显示的内容ViewPort,这层会根据监听Srollable给设置的offset,去将自己的显示内容也就是一个个的sliver展示出来。

中间的一层是Viewport Element,然后就是最后的RenderObject层。RenderObject主要是由展示窗口RenderViewPort和其具体的展示内容条目List(Render sliver)组成。

这样的分层设计方式还是很清晰,解耦的,相对于以往Native将上述的大部分内容聚合在一个View类里面,Flutter在这方面还是做了相应的设计的。尽量将不同职责的内容做了拆分,完成高内聚低耦合,从而能在多变的场景的应用中组合,实现相应的功能。

总的来说,不管是Widget还是RenderObject层,各自都可以对应的分成两部分,一部分负责监听用户手势然后计算自己对应滑动偏移值Offset,还有一部分则是具体展示内容,以及相应地怎么布局。下面我们以一个垂直向下滚动的CustomScrollView为例对它的实现做一些具体的剖析。

 

二、Srollable

2.1  Srollable总述

 

图5  Srollabl

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值