前言
相信不少人在那个三天不打上房揭瓦的年纪中,或多或少干过各种形式的拆家活动,包括且不限于拆工具、拆玩具,甚至拆家具拆电器;
在收获一顿“皮带炒肉”之后,最大的感受除了屁股上的疼痛,就是拆解分析的快感;如果能不多不少零件的前提下再重新组装回去,除了能免于一顿胖揍之外,获得的成就感也是爆棚;
而FLutter中的各个大Widget,也是各种小Widget组合而来,按照它们的说法:Everything is a Widget
那么我今天就要看看,你有多深的道,满满的正能量,岂能被你吓到?
拆解准备
做为一名打小就拆家的资深拆家工程师,对如何拆机械拆家电也是有自己的一些心得:
比如说,初级拆家工程师,拿到小家电第一件事,就是上螺丝刀上锤子暴力拆解;按照个人经验,这种拆解方式,下场一般是一到三天内只能趴着睡觉;
而像我这种资深级别的,拿到不熟悉的小家电,第一件事就是分析构造,寻找可以上手的地方;
所幸Flutter官方就提供了堪比X光的工具,能让我们比较直观的看到整个ListView的构造,那么有请DevTools给大家展示一下ListView的结构,当然,像这种初级Widget,结构不会复杂,层级无非就那么几层,看我一篇文章搞定:
嗯,虽然跟我预想的有那么“亿点点”差距;但是问题不大,多写几篇水文,没啥大不了的;
那么下面结合源码,开始动工
简单分析
单单从上面devTool的DetailTree图中得到的结果,总结一下,listView的Widget树是这样:
ListView
➡PrimaryScrollController
➡ Scrollable
➡ GlowingOverscrollIndicator
➡ NotificationListener<ScrollNotification>
➡ RepaintBoundary
➡ CustomPaint
➡ RepaintBoundary
➡ _ScrollSemantics
➡ _ScrollableScope
➡ Listener
➡ RawGestureDetector
➡ _GestureSemantics
➡ Listener
➡ Semantics
➡ IgnorePointer
➡ Viewport
➡ SliverPadding
➡ MediaQuery
➡ SliverList
除了ListView本身,他还给每个item外面包了一些额外的东西:
KeyedSubtree
➡ AutomaticKeepAlive
➡ KeepAlive
➡ NotificationListener
➡ IndexedSemantics
➡ RepaintBoundary
结合源码中的注释,以及我正宗的工地英语,我们可以简单的对各个widget的功能做一个基本的猜测判断:
- PrimaryScrollController : 用于控制ListView的基本控制器,包括滚动位置;
- Scrollable : A widget that scrolls. 说白了,就是个提供可滑动的组合型widget
- GlowingOverscrollIndicator : 提供过度滚动效果的那个
- NotificationListener : 各种事件的分发监听器_ScrollSemantics
- RepaintBoundary : 在这里和后续的所有RepaintBoundary,都只有一个作用,防止过度多次无用重绘
- CustomPaint : 还记得上面那个GlowingOverscrollIndicator么?你猜猜OverScroll的时候那个提示效果是谁绘制出来的?
- _ScrollSemantics : 根据注释来看,好像没啥大用……结合SemanticsNode来给某些地方增加语义数据(???语义数据是啥???)
- _ScrollableScope : 继承自InheritedWidget,那么用处很明显了,共享提供数据,至于啥数据、有啥用,以后看;
- Listener : 一个提供了触屏手势回调的widget;
- RawGestureDetector : 很经典的手势监听器,跟上面那个Listener差不多一个性质的作用
- _GestureSemantics : 如果需要排除一些额外的手势,那么使用这个widget
- Semantics : 用于给widget树增加一些语义,看注释猜测,好像单纯调试用的,比如说devTool那帮,大概~
- IgnorePointer : 这个就很熟悉了,触摸事件的拦截器
- Viewport : 展示可视范围内的widget
- SliverPadding : 给滑动widget类型专用的Padding小组件
- MediaQuery : 继承自InheritedWidget,跟那个_ScrollableScope一个性质的东西,不过在这里面放的是通用的媒体信息(???是指可视区域么???),比如说窗口大小;
- SliverList : 相当于ListView 基础本体?
在Item这块,组合的Widget功能猜测是这样的:
- KeyedSubtree : 好像就给Item包个Key,这个key默认value是index;作用不明,后续再看
- AutomaticKeepAlive : 说白了,缓存item,好像跟复用有点联系?
- KeepAlive : 跟上面的那个一个效果,具体差别是这块是标记哪些需要保活;
- IndexedSemantics : 看注释,又是给item加个index的,是不是因为KeyedSubtree有存在不是index当key的情况,所以index信息放这里?
整理一下,下面将会对这几个widget做下研究
- PrimaryScrollController(控制器,研究整体流程肯定要涉及这块)
- Scrollable (滑动本体)
- _ScrollableScope(看下里面保存的啥数据)
- Viewport(视窗肯定是相关部分)
- SliverList(列表本体)
item这块:
- KeyedSubtree(看下到底啥用)
- KeepAlive(保活部分,可能涉及复用?)
- IndexedSemantics(这个index保存的作用是?)
目录搞定,开工