flutter 动画

一、隐式(全自动)动画

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

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

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

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

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

AnimatedContainer

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

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

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

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

依然是个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



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 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的。

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

    • 比如AlignTransition,alignment入参是Animation类型,也可以用_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转为Animation

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.可以体验一下,制作一个简单的动画,设置时间节点的关键帧,动画也有补帧动画的感觉

你可能感兴趣的:(flutter 动画)