flutter 动画

一、隐式(全自动)动画

所谓隐式动画就是只需要设置动画目标,过程控制由系统实现

一般是简单点的动画,比如只是简单的宽高变化。当然使用简单不代表功能就简单,下面会有体现

没有循环重播,不用随时中断,没有多方协调,就是从开始运行到结束。

这种动画一般就是隐式动画,使用flutter提供的api,隐式动画一般是Animated...开头。所以,便于学习记忆

还可以自定义隐式动画:TweenAnimationBuilder

AnimatedContainer

\color{red} {该组件是处理盒子级别动画的}

动画盒子,是作用到盒子属性上的,所以盒子有的一些属性,是可以动画效果的。。但是每个widget都有自己的管理,所以,如果想实现盒子里widget的动画就需要别的方式了

实现很简单,就两行代码,AnimatedContainer,duration变量。flutter会隐式的帮我们处理动画过程。

实现简单,但是功能可不简单,container有个decoration属性,该属性能实现的功能是很丰富的。所以,只要是盒子这个级别的所有变化都是可以动画的

不同控件间切换的过渡动画:AnimatedSwitcher

\color{red} {该组件是在子组件发生变化时候处理动画的}

依然是个widget,是个盒子,但是该盒子是用于处理内部child组件切换时候动画的。

也是只有一个属性:duration。flutter会隐式帮我们处理动画过程

但是当子组件没有变化的时候,就没有动画了

比如:AnimatedSwitcher内的child组件是个text,text内容有变化的时候,就不会有动画,这是因为flutter判断child子组件没有发生变化,就没有触发动画过程

所以,只需要给组件设置一个key即可。可以如下简单的设置一下:UniqueKey,表示自己唯一的key

key: UniqueKey()

demo

return AnimatedContainer(
      duration: const Duration(milliseconds: 300),
      width: 200,
      height: 300,
      child: AnimatedSwitcher(
          duration: const Duration(milliseconds: 400),
          //当内容有变化的时候就会触发动画
          child: Text('content', key: UniqueKey(),),
          // 丰富的动画控制
          transitionBuilder: (child, animation) {
            return FadeTransition(
              opacity: animation,
              child: ScaleTransition(
                scale: animation,
                child: child,
              ),
            );
          }
      ),
    );
AnimatedSwitcher.gif

其他的一些可以自行尝试

一般就是Animated...开头的动画组件

  • AnimatedOpacity
  • AnimatedPadding
  • ...

另外动画默认是线性变化的,动画有个curve属性,可以自行尝试

curves官方文档

TweenAnimationBuilder

\color{red} {补间动画,重点在于开始和结束值,flutter帮我们补帧}

\color{green} {代码流程:基于设备帧率,比如60帧,那在duration内flutter帮我们从begin值到end值补} \color{green} {上58帧图画。builder回调1s内会被调60次,把tween当前值传给builder用于控制ui当前状态}

\color{blue} {tip:}
\color{blue} {1、补间动画每次都是从当前值到end的动画过程,所以begin值就相当于一个动画初始值了。}
\color{blue} {2、tween值设置的时候要结合具体动画控制的范围。比如Opacity是从0~1,rotate是0~6.28。}

demo

return TweenAnimationBuilder(
        tween: Tween(begin: 0.0, end: 1.0),
        duration: const Duration(seconds: 2),
        builder: (context, double value, widget) {
          return Opacity(
            opacity: value,
            child: Container(
              width: 200,
              height: 300,
              color: Colors.red,
            ),
          );
        }
    );

补充:平移动画,offset可以直接写到tween里

二、显示(手动控制)动画

\color{red} {隐式动画的流程是系统控制的,大部分工作都是由系统来做的。只是需要我们设置begin和end值。但是有些是}
\color{red} {需要动画一直运行,或者其他的需要我们来控制更多的流程,就需要显示动画了,我们手动控制动画流程}

一般我们使用AnimationController的时候,直接在as中键入stanim使用模板代码:

class xxx extends StatefulWidget {
  const xxx({Key? key}) : super(key: key);

  @override
  _xxxState createState() => _xxxState();
}

class _xxxState extends State<xxx> with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this);
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
  
  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

vsync:垂直信号,由于不同设备刷新频率不一样,告诉系统何时同步动画状态。with SingleTickerProviderStateMixin。vsync:this即可

  • controller是什么?

动画控制器,是跟系统有绑定的关系,通过vsync:this实现屏幕刷新回调builder回调。所以动画的实现最关心的是_controller持续的变动以及builder回调刷新,具体的动画控制可以自行实现,用Tween修改动画范围

比如我们使用RotationTransition的时候turns参数就可以传_controller,turns的入参就可以用AnimationController做一个映射,自己来控制转的圈数:turns:_controller.drive(Tween(end: 4)) 这样实现了_controller的duration内旋转4圈

同理其他...Transition以及AnimatedTransition也一样可以这样用。比如FadeTransition,opacity就可以直接用_controller。

另外可以addListener监听它的值变化,也可以用.value获取动画过程中当前值

  • turns传的controller怎么会是个double呢?

上面说的RotatationTransition,turns参数怎么可以用_controller呢?它是继承自extends Animation<double>的。

  •  
    • 比如ScaleTransition,scale入参Tween(),可以用_controller.drive(Tween())包装为Animation<double>类型。作用就是_controller的duration范围内Tween补帧缩放范围.

    • 比如AlignTransition,alignment入参是Animation<AlignmentGeometry>类型,也可以用_controller.drive()驱动

    return SlideTransition(
        position:_controller.drive(Tween(begin: Offset(0, 0), end: Offset(1, 1))),
    );
    return AlignTransition(
      alignment: _controller.drive(Tween(begin: Alignment.topLeft, end: Alignment.bottomRight)),
      child: const Text("d"),
    );
  • ticker是什么?

英文释义是嘀嗒声,形象的表述为屏幕刷新频率,屏幕要刷新一帧的时候就发一个tick

AnimationController初始化的时候设置的duration范围,有几种控制方式:

1、初始化controller时候,设置lowerBound,upperBound

2、scale:_controller.drive(Tween(begin:0.0, end:1.0))。

这种方式解决的是将Tween<double>转为Animation<double>

3、还有种写法:交错动画

Tween(begin:Offset(0, -0.5), end:Offset(0, 8))
.chain(CurveTween(curve: Curves.elasticInOut))
.chain(CurveTween(curve: Interval(0.0, 0.2)))
.animate(_controller)

chain可以理解为一个函数,就好比g(h(f(x))),函数嵌套,_controller就像是动画的持续过程,这个是跟屏幕刷新有关,但是可以通过多函数复合作用于实际动画效果。比如上面的代码:offset移动和移动速度曲线同时作用于动画过程,就有了从开始到结束沿移动速度曲线进行移动的动画效果

tween-chain.gif

自定义显示动画:AnimatedBuidler

自定义显示动画,一是把动画控制交给AnimationController,二是可以做一些性能优化。比如把动画渲染过程中不需要重绘的组件交给AnimatedBuidler

@override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _controller,
      //_controller控制内持续的调用builder
      builder: (context, child) {
        //每次调用builder,内部所有组件都会重新渲染,注意考虑优化性能
        return Opacity(
          //这里value超过1也没关系,有自动纠错机制。并不会报错。透明度是0~1,如果超过1就还是1不透明的效果
          opacity: _controller.value,
          child: Container(
            width: 300,
            height: 200 + 100 * _controller.value,
            color: Colors.red,
            child: child,
          ),
        );
      },
      //动画执行过程中,不需要变化的部分可以传给AnimatedBuilder,
      // 每次builder回调时候会再传出来,这样就避免了child部分的重新渲染
      child: const Center(
        child: Text(
          "hello",
          style: TextStyle(fontSize: 24),
        ),
      ),
    );
  }

三、其他动画

Flutter动画背后的机制和原理

Hero动画

hero-animation.gif

动画转场更丝滑

但是貌似好像看不出hero动画的牛逼之处,下面再看个例子:

hero-animation2.gif
hero-animation3.gif

hero动画有个特点,就是触发那一刻就变为目标ui然后开始动画

功能强大,使用简单,只需要在开始和目标ui上包括Hero并设置相同唯一的tag即可

直接操作底层的CustomPaint

嵌入式lottie、Rive/Flare插件动画

体验了一下Rive在线动画平台,跟lottie是差不多的,支持的平台也很全。动画制作交给美工就行了,具体实现,都是加载json。提供的都有插件.

https://rive.app.可以体验一下,制作一个简单的动画,设置时间节点的关键帧,动画也有补帧动画的感觉

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,302评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,232评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,337评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,977评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,920评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,194评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,638评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,319评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,455评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,379评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,426评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,106评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,696评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,786评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,996评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,467评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,043评论 2 341

推荐阅读更多精彩内容