本文正在参与「金石方案 . 分割6万现金大奖」


1. 前言: 问题引进

FlexibleSpaceBar 是一个和 SliverAppBar 共生的组件,一般不单独运用。如下所示,在滑动的进程中 FlexibleSpaceBartitle 区域会有缩放的作用。仔细观察会发现,这个缩放是对整个 title 组件收效的,比方 悉数笔记1590 项笔记 文字都有缩放作用。

上滑 下滑
Flutter 组件集录 | FlexibleSpaceBar 组件是怎么炼成的
Flutter 组件集录 | FlexibleSpaceBar 组件是怎么炼成的

那问题来了,怎么只让 悉数笔记 的标题有缩放作用,下面的副标题在滑动进程中一向坚持不变呢?或许咱们怎么监听滑动的分率,完结一些自定义的改换作用呢?这就要从 FlexibleSpaceBar 组件的源码中寻找答案,看它是否支撑这种作用,假如不支撑,咱们该怎么自己完结。


2. 探究: FlexibleSpaceBar 组件的标题怎么完结缩放?

在滑动中,title 组件的内容有缩放作用是实事,这说明在组件的 构建逻辑 中必定存在缩放的改换。所以摆在咱们面前的第一个问题是:

FlexibleSpaceBar 组件的标题怎么 完结缩放 的?

FlexibleSpaceBar 是一个 StatefulWidget,它依赖于 _FlexibleSpaceBarState 状况类来构建组件。所以缩放改换的逻辑也应该在 _FlexibleSpaceBarState#build 办法中:

Flutter 组件集录 | FlexibleSpaceBar 组件是怎么炼成的

class FlexibleSpaceBar extends StatefulWidget {
    //略...
    @override
    State<FlexibleSpaceBar> createState() => _FlexibleSpaceBarState();
}

如下所示,在 _FlexibleSpaceBarState#build 中经过 Transform 完结对标题的缩放,缩放运用的矩阵对象是 scaleTransform :

Flutter 组件集录 | FlexibleSpaceBar 组件是怎么炼成的


3. 探究: FlexibleSpaceBar 组件是怎么感知滑动数据的?

从上面作用中能够看出,SliverAppBar 滑动距离和剩下空间的比值,会作为缩放数值的依据。那么摆在咱们面前的第一个问题是:

FlexibleSpaceBar 组件是怎么感知 滑动数据 的?

如下,是 scaleTransform 矩阵的生成进程,其间的缩放值是一个 补间值,起始值是 widget.expandedTitleScale,也便是初始的缩放值,默认为 1.5。也便是说默认情况下,title 组件会被放大 1.5 倍,然后依据 t 值的大小,向 1 进行补间核算。

比方 t = 0.5 时, scaleValue 的值就在 1.51 的正中间,即 1 + (1.5-1)*0.5 = 1.25,以此类推。现在的关键便是这个 t 是怎么核算的,滑动的数据信息是谁,经过什么渠道 "贩卖的"

---->[_FlexibleSpaceBarState#build]----
final double scaleValue = Tween<double>(begin: widget.expandedTitleScale, end: 1.0).transform(t);
final Matrix4 scaleTransform = Matrix4.identity()
  ..scale(scaleValue, scaleValue, 1.0);

如下是 t 值的核算进程,能够看出滑动的数据是由 FlexibleSpaceBarSettings 组件记载的,毫无疑问,它是一个 InheritedWidget, 子树能够经过它拜访存储的信息,本质上和 Theme 一族是一样的。当 t0 时,表明彻底展开的状况;t1 时,表明 SliverAppBar 剩下空间彻底收起:

Flutter 组件集录 | FlexibleSpaceBar 组件是怎么炼成的


4. 探究: FlexibleSpaceBarSettings 组件在何时入树的?

现在进入最后一个问题,FlexibleSpaceBarSettings 是何时进入组件树的,其间记载的信息又是怎么放入其间的。在 FlexibleSpaceBar 中有一个静态办法,如下所示,会在入参 child 组件的上层包裹住 FlexibleSpaceBarSettings ,其间持有的信息都是经过入参传递的。如下其注释中也有提及:

Flutter 组件集录 | FlexibleSpaceBar 组件是怎么炼成的

也便是说,觉得存入的滑动信息是 FlexibleSpaceBar#createSettings 办法的调用者。到这就好办了,想要知道办法何时被调用的,调试来帮忙。

Flutter 组件集录 | FlexibleSpaceBar 组件是怎么炼成的

如下能够看出,是在 _SliverAppBarDelegate 中被调用的。它最终会作为 SliverPersistentHeader 组件的代理类,用于 _SliverAppBarState 的构建逻辑中。

Flutter 组件集录 | FlexibleSpaceBar 组件是怎么炼成的

到这儿就万事俱备了,从上滑的分析能够知道,滑动的信息从 FlexibleSpaceBarSettings 中能够获取到。另外,FlexibleSpaceBar 状况类的构建逻辑在处理改换时是比较死的,没有露出给运用者可操作性的空间。所以需求完结一些自定义的改换作用,能够 copy 一下 FlexibleSpaceBar 的源码,来魔改一下。


5. 支撑固定副标题

现在来完结一下固定副标题,作用如下,在滑动进程中 1590 项笔记 副标题一向坚持不变。

上滑 下滑
Flutter 组件集录 | FlexibleSpaceBar 组件是怎么炼成的
Flutter 组件集录 | FlexibleSpaceBar 组件是怎么炼成的

现在将源码拷贝一份,命名为 DiyFlexibleSpaceBar,在其间定义 fixedSubtitle 结构入参,作为副标题的插槽。

Flutter 组件集录 | FlexibleSpaceBar 组件是怎么炼成的

final Widget? fixedSubtitle;

然后在源码组件状况类的 构建逻辑 中,经过 Column 供给一个插槽即可,如下所示:

Flutter 组件集录 | FlexibleSpaceBar 组件是怎么炼成的

然后运用 DiyFlexibleSpaceBar 组件,供给 fixedSubtitle 组件即可:

Flutter 组件集录 | FlexibleSpaceBar 组件是怎么炼成的


6. 将滑动分度值露出出去

有时候咱们期望监听到滑动的进展,从而能够在 DiyFlexibleSpaceBar 外部,处理自定义的滑动作用。比方下图中,标题的右侧有一个小风车,能够随着滑动的进展旋转:

上滑 下滑
Flutter 组件集录 | FlexibleSpaceBar 组件是怎么炼成的
Flutter 组件集录 | FlexibleSpaceBar 组件是怎么炼成的

首先,定义一个 FractionalBuilder 的函数类型,用于回调 t 数值来返回组件 Widget; 然后在 DiyFlexibleSpaceBar 中定义 titleIconBuilder 成员:

typedef FractionalBuilder = Widget Function(double t);
class DiyFlexibleSpaceBar extends StatefulWidget {
  const DiyFlexibleSpaceBar({
    /// 略...
    this.titleIconBuilder,
    final FractionalBuilder? titleIconBuilder;

在构建逻辑在触发 titleIconBuilder 结构组件,参数 t 就能够从这儿露出出去:

Flutter 组件集录 | FlexibleSpaceBar 组件是怎么炼成的

然后外界能够感知到 t 的存在,以此操控风车旋转视点即可。关于风车的绘制,参阅 《Flutter 绘制集录 | 第四画 – 风车》

Flutter 组件集录 | FlexibleSpaceBar 组件是怎么炼成的


Flutter 供给的组件,只能满意大多数的运用场景,关于特别的需求,可能是不支撑的。这时便是检测一位编程者能力的机遇了,能看懂源码,并能以此进行改善,来完结需求就显得极为重要。希望我们能够在日常开发中 多做推敲 ,而不是遇事就 伸手去要。 那本文就到这儿,谢谢观看 ~