Flutter 动画学习

1 篇文章 0 订阅
1 篇文章 0 订阅

Flutter 动画(Animation)官方文档地址:https://api.flutter.dev/flutter/animation/animation-library.html

一、隐式(全自动)动画

在Flutter中,隐式动画(Implicit Animation)是一种自动播放的动画效果,只要Widget发生改变,就会自动播放一个过渡动画。大部分以Animated开头的Widget都是带有隐式动画效果的控件。

  • 只在自身属性产生变化时产生动画,当子控件属性发生变化时不会产生动画效果。

1. AnimatedContainer / AnimatedOpacity / AnimatedPadding

  • duration:定义动画持续的时间。duration:Duration(seconds/milliseconds: VALUE),VALUE不能为小数,只能为整数。
  • Curves:控制动画的播放效果。默认是线性(linear)

2. AnimatedSwitch

用于在不同的控件之间来回切换时填充动画效果。当AnimatedSwitch内部的子控件发生变化时,就会自动播放一个动画效果。

当在同一类控件之间切换时,不会产生动画效果。例如:两个内容不同的Text()来回切换,不会有动画效果。在这种情况下想要产生切换动画效果,需要添加关键字key:ValueKey("XXX")或者直接使用key:UniqueKey(),来标志其唯一性。

  • transitionBuilder:来控制切换的动画效果。

AnimatedCrossFaded是优化版本的AnimatedSwitch

3. 补间动画(TweenAnimationBuilder)

在duration中规定的时间段内,会根据tween自动生成补间数值不停的调用builder,同时将该补间数值传递给builder中的value,从而渲染出动画效果。

  • duration:动画持续的时间
  • tween:单词between的简拼,需要定义 beginend 属性,即动画开始和结束的两个关键帧,Flutter自动补全中间的。
  • builder:需要return一个Widget,最终进行渲染。其中的value值会为tween中补间的数值。

其中tween中的begin只有在程序刚运行的时候,从begin运行到end,以后在改变数值,会从当前的数值运行到新定义的end,一开始定义的begin就不再使用。如果不传入begin,程序会自动将end的值赋值给begin。

 

二、显示控件

 

当我们需要创建无限循环的动画,而不是在两个值之间过渡的动画时,就需要使用显示控件来实现。大部分都是以Transaction结尾。例如RotationTransactionSlideTransitionScaleTransition

1. RotationTransaction

需要定义一个Animated<double>来控制动画的运转。我们可以使用Flutter提供的AnimationController来实现。

  • turns:控制旋转的属性,需要一个Animated<double>类型的值。
//SingleTickerProviderStateMixin:获取屏幕刷新的数据,满足不同设备的刷新频率
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {


//定义AnimationController
  AnimationController _controller;

//在该State开始时,初始化AnimationController
  @override
  void initState() {
    super.initState();

    _controller = AnimationController(//填充数值
      duration: Duration(seconds: 1),//定义持续的时间
      lowerBound:0.0,//定义填充数字的下限,默认为0.0
      upperBound:1,//定义填充数值的上限,默认为1.0
      vsync: this,//使用了SingleTickerProviderStateMixin,这里直接将vsync赋值为this
    );
  }

//在State结束时,释放,防止内存泄漏
  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    _controller.dispose();
  }

...
      body: Center(
        child: RotationTransition( //显示动画控件
          turns: _controller,//使用controller进行控制
          child: Center(
            child: Container(
              width: 200.0,
              height: 200.0,
              color: Colors.blueAccent,
              child: Text(
                'Hello World',
                style: TextStyle(
                  fontSize: 50.0,
                  fontWeight: FontWeight.w800,
                ),
              ),
            ),
          ),
        ),
      ),
 floatingActionButton: FloatingActionButton(
        onPressed: (){
          _controller.forward();//转动一次
          //_controller.repeat();//不停的转动。0——>1;0——1
          //_controller.repeat(reverse:true); //从0——>1;1——>0
          //_controller.stop();//原地停止转动
          //_controller.reset();//重置
            
        },
...

   }
}


改变AnimationController的范围除了可以使用lowerBound和UpperBound以外,还可以在XXXTransaction(  )中使用controller的地方调用其drive方法。例如ScaleTransition:

  child: ScaleTransition(
          scale: _controller.drive(Tween(begin:0.5,end:2.0)),
        //scale: Tween(begin:0.5,end:2.0)//另一种写法,方便叠加tween
        //       .chain(CurveTween(curve:Curves.elasticInOut))//添加一个弹性效果
        //       .chain(CurveTween(curve:Interval(0.8,1)))//在0.8到1区间内运动完成动画,其它时间不动
        //       .animate(_controller),
          child: Center(
            child: Container(
              width: 200.0,
              height: 200.0,
              color: Colors.blueAccent,
              child: Text(
                'Hello World',
                style: TextStyle(
                  fontSize: 50.0,
                  fontWeight: FontWeight.w800,
                ),
              ),
            ),
          ),
        ),

2. 自定义控件

使用AnimatedBuilder控件绘制。

AnimatedBuilder(
    animation:_controller,//手动控制器
    builder:(BuildContext context, Widget child){
        return WIDGET(//child优化
              
        ),
    }
    child://此处的child为一个AnimatedBuilder的属性,将不需要更新的Widget放在这里,每次渲染时将跳过此部分内容
),
  • animation:Animated<double>
  • builder:每当animation发生变化时,builder就会每一帧重新绘制一次

可以通过AnimatedController来实现不是从0-1数值变化的动画,比如:将container的height从100——>300。

我们都知道,AnimationController中的控制器是一个在0——1之间变化的Animated<double>,对于Opacity这种在0——1之间变化的属性可以满足需求。但是对于像高度等变化范围并不局限于0——1之间的属性来说,就不能直接通过AnimationController来控制属性变化。我们可以通过Tween来确定一个区间,然后通过其evaluate函数来对AnimationController这个0-1之间的数值变换进行函数运算,从而可以得到一个不局限于0——1之间的区间。

 child: Container(
              width: 200.0,
              height: Tween(begin: 200.0,end: 500.0).evaluate(_controller),
              color: Colors.blueAccent,
              child: Text(
                'Hello World',
                style: TextStyle(
                  fontSize: 50.0,
                  fontWeight: FontWeight.w800,
                ),
              ),
            ),

还可以有一下写法来让代码看起来更加整洁

...
Widget build(BuildContext context) {

    final Animation heightAnimation = Tween(begin: 200.0,end: 300.0).animate(_controller);

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: RotationTransition(
          turns: _controller,
          child: Center(
            child: Container(
              width: 200.0,
              height: heightAnimation.value,
              color: Colors.blueAccent,
              child: Text(
                'Hello World',
                style: TextStyle(
                  fontSize: 50.0,
                  fontWeight: FontWeight.w800,
                ),
              ),
            ),
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          _controller.stop();
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
...

三、主动画(Hero)

在两个界面之间跳转的过程中对某元素添加动画效果。

对需要添加过渡效果的部分都添加上Hero标签

  • tag:唯一的属性,只有需要过渡的两个部分具有相同的tag

 

四、CustomPainter

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值