Flutter | AnimatedCrossFade - 交叉淡入 Widget

主要来讲解 AnimatedCrossFade 该组件使用的方式和大致可以使用的场景。

先来了解一下 AnimatedCrossFade

1. 首先看一下官方介绍

A widget that cross-fades between two given children and animates itself between their sizes.

在两个子 Widget 之间交叉淡入并在其大小之间设置动画的小部件。

其中「交叉淡入」其实是电影中的术语,意思就是由一个要素进入另一个要素。

也就是「由一个 Widget 进入另一个 Widget」

2. 再来看一下构造函数

const AnimatedCrossFade({
  Key key,
  @required this.firstChild,
  @required this.secondChild,
  this.firstCurve = Curves.linear,
  this.secondCurve = Curves.linear,
  this.sizeCurve = Curves.linear,
  this.alignment = Alignment.topCenter,
  @required this.crossFadeState,
  @required this.duration,
  this.reverseDuration,
  this.layoutBuilder = defaultLayoutBuilder,
}) : assert(firstChild != null),
assert(secondChild != null),
assert(firstCurve != null),
assert(secondCurve != null),
assert(sizeCurve != null),
assert(alignment != null),
assert(crossFadeState != null),
assert(duration != null),
assert(layoutBuilder != null),
super(key: key);

可以看到必要的参数有四个:

1.

firstChild:第一个 childWidget,也就是直接展示的那个

2.

secondChild:第二个 childWidget,切换时显示的

3.crossFadeState:final CrossFadeState crossFadeState,是一个枚举:

um CrossFadeState {
  /// Show the first child ([AnimatedCrossFade.firstChild]) and hide the second
  /// ([AnimatedCrossFade.secondChild]]).
  showFirst,

  /// Show the second child ([AnimatedCrossFade.secondChild]) and hide the first
  /// ([AnimatedCrossFade.firstChild]).
  showSecond,
}

4.duration:不多说,动画切换的时间

有了这四个参数,我们就能用它了。

跟着官方 Demo 来写一下

看一下代码:

AnimatedCrossFade(
  duration: const Duration(seconds: 3),
  firstChild: const FlutterLogo(style: FlutterLogoStyle.horizontal, size: 100.0),
  secondChild: const FlutterLogo(style: FlutterLogoStyle.stacked, size: 100.0),
  crossFadeState: _first ? CrossFadeState.showFirst : CrossFadeState.showSecond,
)

先看效果:

这不就跟 AnimatedSwitcher 一样吗?

这么看起来确实其实没什么屌的,官方的demo只是给你一个简单的使用方法而已。

我们可以从刚才的官方介绍里找到一点不一样的地方:「并在其大小之间设置动画」

那我们给他们套上颜色,并且改一下大小来看看:

有内味了是不,可是这切换回来的时候怎么有点鬼畜的感觉?不要着急。

稍微深入一下源码

为什么会有鬼畜的效果?遇事不决看源码,去年在写文章的时候说过,Flutter 的源码里有特别多的注释和 demo。那就先来看一下他的注释:

/// The animation is controlled through the [crossFadeState] parameter.
/// [firstCurve] and [secondCurve] represent the opacity curves of the two
/// children. The [firstCurve] is inverted, i.e. it fades out when providing a
/// growing curve like [Curves.linear]. The [sizeCurve] is the curve used to
/// animate between the size of the fading-out child and the size of the
/// fading-in child.
///
/// This widget is intended to be used to fade a pair of widgets with the same
/// width. In the case where the two children have different heights, the
/// animation crops overflowing children during the animation by aligning their
/// top edge, which means that the bottom will be clipped.
///
/// The animation is automatically triggered when an existing
/// [AnimatedCrossFade] is rebuilt with a different value for the
/// [crossFadeState] property.


动画是通过[crossFadeState]参数控制的。[firstCurve]和[secondCurve]表示两个孩子的不透明度曲线。[firstCurve]是倒置的,即当提供诸如[Curves.linear]之类的增长曲线时,它会淡出。[sizeCurve]是用于在淡出子项的大小和淡入子项的大小之间进行动画处理的曲线。

此小部件用于淡化一对具有相同宽度的小部件。如果两个孩子的高度不同,则动画会在动画过程中通过对齐它们的顶部边缘来裁剪溢出的child,这意味着将裁剪底部。

当以不同的值重建现有的[AnimatedCrossFade]时,动画会自动触发。

画重点:如果两个孩子的高度不同,则动画会在动画过程中通过对齐它们的顶部边缘来裁剪溢出的child,这意味着将裁剪底部。

对齐顶部边缘和裁剪底部,那我们还是先来看一下 AnimatedCrossFade 是如何做到 在大小之间做动画的

具体重点代码如下:

@override
Widget build(BuildContext context) {
  // ...
  // 去掉于此无关代码
  return ClipRect(
    child: AnimatedSize(
      alignment: widget.alignment,
      duration: widget.duration,
      reverseDuration: widget.reverseDuration,
      curve: widget.sizeCurve,
      vsync: this,
      child: widget.layoutBuilder(topChild, topKey, bottomChild, bottomKey),
    ),
  );
}

// -----------------------------------------
//           defaultLayoutBuilder
// -----------------------------------------
static Widget defaultLayoutBuilder(Widget topChild, Key topChildKey, Widget bottomChild, Key bottomChildKey) {
  return Stack(
    overflow: Overflow.visible,
    children: <Widget>[
      Positioned(
        key: bottomChildKey,
        left: 0.0,
        top: 0.0,
        right: 0.0,
        child: bottomChild,
      ),
      Positioned(
        key: topChildKey,
        child: topChild,
      ),
    ],
  );
}

如果我们没有给 layoutBuilder 这个参数的时候,默认是有一个 defaultLayoutBuilder 的,这个里面就有前面所看到的那句话 对齐它们的顶部边缘来裁剪,所以当我们从第二个 child 回到第一个 child 的时候,就会发生宽度突然变化,解决办法也很简单:

layoutBuilder: (topChild, topChildKey, bottomChild, bottomChildKey) {
  return Stack(
    overflow: Overflow.visible,
    alignment: Alignment.center,
    children: <Widget>[
      Positioned(
        key: topChildKey,
        child: topChild,
      ),
      Positioned(
        key: bottomChildKey,
        top:0,
        child: bottomChild,
      ),
    ],
  );
}

把第二个的 leftright 去掉,并且加上 alignment: Alignment.center,这样就完成了,再来看一下效果:

思考题

鉴于 AnimatedCrossFade 的这个特性,我做了一个小 Demo,效果如下:

这玩意能玩出什么效果?

美团外卖Flutter动态化实践

动态化是 Flutter 无法避开的话题。本文从 Flutter 的特点讲起, 阐述了美团外卖团队在整个 Flutter 动态化上探索的心路历程,还有设计理念、核心原理以及业务应用的经验。本文的视角也不局限于框架本身,更多思考了在解决问题的过程中技术团队需要做的事情,希望能对大家有所启发和帮助。

发布于:5天以前  |  26次阅读  |  详细内容 »

Flutter 上的内存泄漏监控

Flutter 所使用的 Dart 语言具有垃圾回收机制,有垃圾回收就避免不了会内存泄漏。在 Android 平台上有个内存泄漏检测工具 LeakCanary[1], 它可以方便地在 debug 环境下检测当前页面是否泄漏。本文将会带你实现一个 Flutter 可用的 LeakCanary,并讲述怎么用该工具检测出了 1.9.1 Framework 上的两个泄漏。

发布于:14天以前  |  63次阅读  |  详细内容 »

网易支付-高性能NEJFlutter小程序动态化架构实践

大家好,今天跟大家分享的主题是《NEJFlutter小程序动态化高性能架构》,这是关于网易支付团队在Flutter小程序动态化方向上尝试的一套技术解决方案,一句话介绍NEJFlutter,就是用JavaScript开发业务逻辑、Flutter开发UI布局的小程序架构,性能堪比原生Flutter应用;

发布于:26天以前  |  127次阅读  |  详细内容 »

Flutter卡顿问题的监控与思考

使用Flutter技术构建的应用,一直以高性能高流畅度著称。但是随着应用复杂度越来越高,Flutter会出现一些页面流畅度明显低于Native的情况,甚至可能发生一些卡顿。而很多时候卡顿都发生在线上,即使获得了用户的操作路径,也难以重现。如果我们有一套卡顿监控系统,能够帮助我们捕获到卡顿时的堆栈,那么在发生卡顿的时候,我们就可以定位到具体是哪个函数引起的卡顿,从而解决这些问题。

发布于:26天以前  |  125次阅读  |  详细内容 »

最多阅读

在Flutter中添加资源和图片 1年以前  |  2363次阅读
Flutter的手势GestureDetector分析详解 1年以前  |  1889次阅读
发布Flutter开发的iOS程序 1年以前  |  1675次阅读
Flutter插件详解及其发布插件 1年以前  |  1674次阅读
Flutter Widget框架概述 1年以前  |  1423次阅读
在Flutter中发起HTTP网络请求 1年以前  |  1403次阅读
使用Inspector检查用户界面 1年以前  |  1374次阅读
JSON和序列化 1年以前  |  1280次阅读
Flutter框架概览 1年以前  |  1246次阅读
Flutter 状态管理指南之 Provider 1年以前  |  1232次阅读
为Flutter应用程序添加交互 1年以前  |  1191次阅读
使用自定义字体 1年以前  |  1179次阅读
Flutter for Web详细介绍 1年以前  |  1137次阅读
Flutter路由详解 1年以前  |  1080次阅读
处理文本输入 1年以前  |  1076次阅读
发布Flutter开发的Android程序 1年以前  |  1015次阅读
使用包来开发Flutter应用 1年以前  |  1011次阅读
编写国际化Flutter App 1年以前  |  989次阅读