信任关于 Flutter 开发的大家来说, ListView 的 shrinkWrap 装备都不会生疏,如下图所示,每当遇到类似的 unbounded error 的时分,总会有第一反应便是给 ListView 加上 shrinkWrap: true 就能够解决问题,那为什么现在会说 shrinkWrap 即将被“扔掉”呢?

Flutter 小技巧之滑动控件即将“抛弃” shrinkWrap 属性

其实说彻底“扔掉”也不大严谨,从现在官方的规划来看, shrinkWrap 装备将从滑动控件里弃用,由于团队觉得现阶段的开发人员大多数时分不知道它的实际意义,仅仅单纯运用它解决问题,在运用过程中容易呈现过错的功能损耗而不自知

Flutter 小技巧之滑动控件即将“抛弃” shrinkWrap 属性

当然,这个提议并不是说彻底废除 shrinkWrap 的支持,而且类似经过全新的 Widget 来代替,用更形象的命名,例如 NonLazyListView 等。

Flutter 小技巧之滑动控件即将“抛弃” shrinkWrap 属性

现在这个提议的等级是 P1 ,所以假如不意外的话,它的推动会很快

那么 shrinkWrap 为什么会带来功能问题?它常用在什么场景?为什么会需要被提高到 P1 来进行调整?

首要咱们需要简略了解 Flutter 滑动列表的完结和 shrinkWrap 的作用,在《带你了解 Flutter 中的滑动列表完结》里咱们介绍过,Flutter 里的滑动列表是由 ViewportScrollable 和相应的 Sliver 三部分组成

ListView 为例,如下图所示是 ListView 滑动过程的改变,其中:

  • 绿色的 Viewport 便是咱们看到的列表窗口巨细;
  • 紫色部分便是处理手势的 Scrollable,让黄色部分 SliverListViewport 里发生滑动;
  • 黄色的部分便是 SliverList , 当咱们滑动时其实便是它在 Viewport 里的方位发生了改变;

Flutter 小技巧之滑动控件即将“抛弃” shrinkWrap 属性

所以 ListView 之所以能够“无限”滑动,便是由于首要有一个固定巨细「窗口」, 只要在进入和接近「窗口」的 Item 才会被布局烘托,然后保证了列表的功能。

可是这也带来了一个问题,如下图 1 的代码所示,它就由于 Column 的特性,没办法直接核算得到 Viewport 的巨细,所以会抛出过错。

Flutter 小技巧之滑动控件即将“抛弃” shrinkWrap 属性
Flutter 小技巧之滑动控件即将“抛弃” shrinkWrap 属性
Flutter 小技巧之滑动控件即将“抛弃” shrinkWrap 属性

有时分咱们会如上图 2 所示,经过给 ListView 加一个 Expanded 来解决,这样 ListView 会充溢 Column 的剩下空间,然后得到一个固定的 Viewport 巨细。

可是当咱们希望此刻 ListView 不充溢,还能够居中显示的时分,就会选用如上图 3 所示那样,添加一个 shrinkWrap: true

虽然这个比如没有意义,可是它展现了 shrinkWrap 的“首要”场景,另外 shrinkWrap 也常被用于 ListView 嵌套 ListView 这种不规范运用的场景中

shrinkWrap 的完结原理是什么?简略来说,现阶段 shrinkWrap:true 的时分,在滑动控件内部会选用一个特别的 ShrinkWrappingViewport 「窗口」进行完结。

Flutter 小技巧之滑动控件即将“抛弃” shrinkWrap 属性

ShrinkWrappingViewportViewport 的不同之处在于 :

  • Viewport 是填充溢主轴方向的巨细
  • ShrinkWrappingViewport 是调整自身巨细去匹配主轴方向中 Item 的巨细,而这种“缩短”的行为成本会变高,由于窗口巨细需要经过 child 去“确定”。

例如,如下图所示,在 ListView 里,咱们将 itemCount 修改为 400 ,然后打印每个 Item 的 build ,由于 shrinkWrap 的作用,能够看到 400 个 child 都被输出。

Flutter 小技巧之滑动控件即将“抛弃” shrinkWrap 属性

相同,在 Inspector 的 Widget Tree 里能够看到 400 个 child 都构建完结,虽然他们还远没有在 ViewPort 展现出来,所以 shrinkWrapListView 失去了懒加载的作用。

相反,如下图代码所示,假如去掉 shrinkWrap ,在 Expand 的作用下 ListView 有了固定巨细的 ViewPort ,此刻就算是 itemCount 是 400 ,可是也只会依据 ViewPort 构建所需的 19 个 child 。

Flutter 小技巧之滑动控件即将“抛弃” shrinkWrap 属性

就算是由于滑动发生改变,正常情况下的 ListView 也保持着「固定」的长度,例如滑动到 160 的 index 的时分,此刻开始的 ListTitle 的 index 是 135 ,而不会像 shrinkWrap 一样保持着全员 child 的构建。

Flutter 小技巧之滑动控件即将“抛弃” shrinkWrap 属性

怎么要深究的话,其中关键点之一就在于 updateOutOfBandData 方法完结的不同,在一般 Viewport 里, updateOutOfBandData 方法仅仅用于核算 maxScrollExtent ,而如下图 1 所示,ShrinkWrappingViewport 里会对每个 child 的 maxPaintExtent 进行累计。

Flutter 小技巧之滑动控件即将“抛弃” shrinkWrap 属性
Flutter 小技巧之滑动控件即将“抛弃” shrinkWrap 属性

累计之后的得到的 _shrinkWrapExtent 最终会转化为 ShrinkWrappingViewport 自己的 size ,这也是 ShrinkWrappingViewport 为什么能够依据 child 调整「窗口」巨细的原因。

所以,在此之前或许开发者经常经过简略的 shrinkWrap 来解决问题,而比较少考虑 shrinkWrap 的完结原理,或许说缺少了解它的作用,然后带来了一些隐形的功能问题而不自知,所以这也是为什么这次会有该调整的原因:

shrinkWrap 迁移到全新控件能够更直观让大家了解其作用,而其实大部分运用 shrinkWrap 的场景能够被其他完结代替。

  • 例如前面提到的 ListView 嵌套 ListView 的场景,与其对经过装备 shrinkWrap 来完结,不如经过 CustomScrollView 结合不同 SliverList 或许其他 Sliver 组建完结组合。

  • 而假如 child 并不多,其实也能够直接经过 SingleChildScrollView + Column 来完结,它在必定程度上作用和 shrinkWrap 类似。

所以,到这里你应该知道了 shrinkWrap 的完结逻辑和作用,其实本次首要也是想经过这个 new feature 变动,带大家重新认识下 shrinkWrap由于接下来,它就不再叫 shrinkWrap 了,或许你以后也应该很少用到它