跳转至

动画

内置的全自动隐式动画控件

Animated开头

curve: Curves.linear,//线性变换(可以修改各种曲线)

AnimatedContainer动画盒子

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

  @override
  State<Demo> createState() => _DemoState();
}

class _DemoState extends State<Demo> {
  double _height = 300;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: Center(
        ///只对AnimatedContainer自己的属性参数改变有动画,对child的改变没有动画
        child: AnimatedContainer(
          width: 300,
          height: _height,
          // color: Colors.blue,
          //持续时间
          duration: const Duration(milliseconds: 500),
          child: const Center(
            child: Text(
              'Hi',
              style: TextStyle(fontSize: 72),
            ),
          ),
          decoration: BoxDecoration(
            ///渐变色LinearGradient
            gradient: const LinearGradient(
              begin: Alignment.bottomCenter,
              end: Alignment.topCenter,
              colors: [Colors.orange, Colors.white],
              ///哪个地方有过渡动画
              stops: [0.2, 0.3],
            ),
            //边框
            boxShadow: const [BoxShadow(spreadRadius: 25, blurRadius: 25)],
            //圆角
            borderRadius: BorderRadius.circular(150),
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            _height += 100;
            if (_height > 500) _height = 200;
          });
        },
        tooltip: 'change',
        child: Icon(Icons.add),
      ),
    );
  }
}

AnimatedSwitcher

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

class _DemoState extends State<Demo> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: const Center(
        child: AnimatedSwitcher(
          duration: Duration(seconds: 10),
          child: Center(
            child: CircularProgressIndicator(),
          ), //Image.network("https://i.imgur.com/9tvsYY0.png"),
        ),
      ),
    );
  }
}

AnimatedOpacity

class _DemoState extends State<Demo> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: Center(
        child: AnimatedOpacity(
          opacity: 0.5,
          duration: const Duration(milliseconds: 500),
          child: Container(
            width: 300,
            height: 300,
            color: Colors.red,
          ),
        ),
      ),
    );
  }
}

AnimatedPadding

class _DemoState extends State<Demo> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: AnimatedPadding(
        curve: Curves.linear,
        duration: const Duration(milliseconds: 500),
        padding: const EdgeInsets.all(0),
        child: Container(
          width: 300,
          height: 300,
          color: Colors.red,
        ),
      ),
    );
  }
}

TweenAnimationBuilder补间动画

内置的不够时,使用补间动画。

tween:意思就是between之间 例如0~1,类似关键帧。1s有60帧

TweenAnimationBuilder(
  //程序刚开始的时候begin有意义,之后再变化的时候就是从当前的值到end
  tween: Tween(begin: 0.0, end: 1.0),

  duration: const Duration(milliseconds: 500), 

  //在时间内,不断的叫下面的build函数,value是不断变化的(begin~end)
  //简单的控件,里面是child。复杂的时候(例:ListView里面是bulid)
  builder: (BuildContext context, value, Widget? child) {
    return Opacity(
      opacity: value,
      child: Container(
        width: 300,
        height: 300,
        color: Colors.red,
      ),
    );
  },
),
class _DemoState extends State<Demo> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: Center(
        child: TweenAnimationBuilder(
          tween: Tween(begin: 0.0, end: 1.0),
          duration: const Duration(milliseconds: 500), 
          builder: (BuildContext context, double value, Widget? child) {
            return Opacity(
              opacity: value,
              child: Container(
                width: 300,
                height: 300,
                color: Colors.red,
              ),
            );
          },
        ),
      ),
    );
  }
}

Transform

Transform.scale缩放

class _DemoState extends State<Demo> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: Center(
        child: TweenAnimationBuilder(
          tween: Tween(begin: 1.0, end: 1.2), 
          duration: const Duration(milliseconds: 500),
          builder: (BuildContext context, double value, Widget? child) {
            return Container(
              width: 300,
              height: 300,
              color: Colors.red,
              child: Center(
                child: Transform.scale(
                  //4X4矩阵
                  scale: value,
                  child: const Text(
                    'hi',
                    style: TextStyle(fontSize: 72),
                  ),
                ),
              ),
            );
          },
        ),
      ),
    );
  }
}

Transform.rotate旋转

class _DemoState extends State<Demo> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: Center(
        child: TweenAnimationBuilder(
          tween: Tween(begin: 0.0, end: 6.28), 
          duration: const Duration(milliseconds: 500),
          builder: (BuildContext context, double value, Widget? child) {
            return Container(
              width: 300,
              height: 300,
              color: Colors.red,
              child: Center(
                child: Transform.rotate(
                  //0~2Π 6.28
                  angle: value,
                  child: const Text(
                    'hi',
                    style: TextStyle(fontSize: 72),
                  ),
                ),
              ),
            );
          },
        ),
      ),
    );
  }
}

Transform.translate平移

class _DemoState extends State<Demo> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: Center(
        child: TweenAnimationBuilder(
          tween: Tween(
              begin: const Offset(0.0, -10.0),
              end: const Offset(20.0, 0.0)),
          duration: const Duration(milliseconds: 500),
          builder: (BuildContext context, Offset value, Widget? child) {
            return Container(
              width: 300,
              height: 300,
              color: Colors.red,
              child: Center(
                child: Transform.translate(
                  //横坐标和纵坐标位移多少单位
                  offset: value,
                  child: const Text(
                    'hi',
                    style: TextStyle(fontSize: 72),
                  ),
                ),
              ),
            );
          },
        ),
      ),
    );
  }
}

显式(手动控制)动画

Transition结尾

SingleTickerProviderStateMixin

SingleTickerProviderStateMixin是Flutter库中的一个mixin,它用于提供单个Ticker(计时器)。

在Flutter中,"Ticker"是一个计时器对象,它会在每个动画帧调用它的回调。它可以用于创建平滑的动画效果。例如,你可能会创建一个每秒60次调用其回调的Ticker,这样你的动画就会以60帧/秒的速度运行。

当你的Widget需要监听一个动画(例如,一个AnimationController)时,你需要一个Ticker。AnimationController需要一个TickerProvider来生成其Ticker。如果你的Widget只需要监听一个动画,那么你可以使用SingleTickerProviderStateMixin。如果你的Widget需要监听多个动画,那么你应该使用TickerProviderStateMixin

这个mixin提供的Ticker会自动在Widget被dispose时停止,以防止内存泄漏。

这是使用SingleTickerProviderStateMixin的一个简单示例:

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> with SingleTickerProviderStateMixin {
  AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this, // 当前类是TickerProvider
      duration: const Duration(seconds: 2),
    );
  }

  @override
  void dispose() {
    _controller.dispose(); // 需要在Widget被dispose时停止AnimationController
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

在这个示例中,_MyWidgetState类使用了SingleTickerProviderStateMixin,这使得它可以作为一个TickerProvider。然后,这个TickerProvider被用来创建一个AnimationController

无尽旋转的显示动画

//SingleTickerProviderStateMixin获取设备垂直同步
///ticker:屏幕每次刷新的时候就会产生一个tick
class _DemoState extends State<Demo> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  @override
  void initState() {
    _controller = AnimationController(
      duration: const Duration(milliseconds: 500),
      vsync: this,
    );
    super.initState();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: Center(
        child: RotationTransition(
          turns: _controller, //0.5就是半圈
          child: const Icon(
            Icons.refresh,
            size: 100,
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            // _controller.forward();//转一圈
            _controller.repeat(); //重复转
            // _controller.reset(); //回到原来的状态
            // _controller.stop();//原地停止
          });
        },
        tooltip: 'change',
        child: const Icon(Icons.add),
      ),
    );
  }
}

动画控制器

FadeTransition:消失

class _DemoState extends State<Demo> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  @override
  void initState() {
    // TODO: implement initState
    _controller = AnimationController(
      duration: const Duration(milliseconds: 500),
      // //上下限,默认0~1
      // lowerBound: 3.0,
      // upperBound: 5.0,
      vsync: this,
    );
    _controller.addListener(() {
      print("aaa${_controller.value}"); //value介于lowerBound~upperBound
    });
    super.initState();
  }

  @override
  void dispose() {
    // TODO: implement dispose
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: Center(
        //渐渐消失
        child: FadeTransition(
          opacity: _controller,
          child: const Icon(
            Icons.refresh,
            size: 100,
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            _controller.forward(); //转一圈
            // _controller.repeat(); //重复转
            // _controller.reset(); //回到原来的状态
            // _controller.stop(); //原地停止
          });
        },
        tooltip: 'change',
        child: const Icon(Icons.add),
      ),
    );
  }
}

ScaleTransition:缩放

class _DemoState extends State<Demo> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  @override
  void initState() {
    // TODO: implement initState
    _controller = AnimationController(
      duration: const Duration(milliseconds: 500),
      // //上下限,默认0~1
      // lowerBound: 3.0,
      // upperBound: 5.0,
      vsync: this,
    );
    _controller.addListener(() {
      print("aaa${_controller.value}"); //value介于lowerBound~upperBound
    });
    super.initState();
  }

  @override
  void dispose() {
    // TODO: implement dispose
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: Center(
        //渐渐消失
        child: ScaleTransition(
          scale: _controller,
          child: const Icon(
            Icons.refresh,
            size: 100,
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            // _controller.forward(); //转一圈
            _controller.repeat(reverse: true); //重复转
            // _controller.reset(); //回到原来的状态
            // _controller.stop(); //原地停止
          });
        },
        tooltip: 'change',
        child: const Icon(Icons.add),
      ),
    );
  }
}

控制器串联补间Tween和曲线

class _DemoState extends State<Demo> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  @override
  void initState() {
    // TODO: implement initState
    _controller = AnimationController(
      duration: const Duration(milliseconds: 500),
      // //上下限,默认0~1
      // lowerBound: 3.0,
      // upperBound: 5.0,
      vsync: this,
    );
    _controller.addListener(() {
      print("aaa${_controller.value}"); //value介于lowerBound~upperBound
    });
    super.initState();
  }

  @override
  void dispose() {
    // TODO: implement dispose
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: Center(
        //渐渐消失
        child: ScaleTransition(
          //Tween改变开始和结束
          scale: _controller.drive(Tween(begin: 0.0, end: 1.0)),
          child: const Icon(
            Icons.refresh,
            size: 100,
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            // _controller.forward(); //转一圈
            _controller.repeat(reverse: true); //重复转
            // _controller.reset(); //回到原来的状态
            // _controller.stop(); //原地停止
          });
        },
        tooltip: 'change',
        child: const Icon(Icons.add),
      ),
    );
  }
}
class _DemoState extends State<Demo> with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  @override
  void initState() {
    // TODO: implement initState
    _controller = AnimationController(
      duration: const Duration(milliseconds: 500),
      // //上下限,默认0~1
      // lowerBound: 3.0,
      // upperBound: 5.0,
      vsync: this,
    );
    _controller.addListener(() {
      print("aaa${_controller.value}"); //value介于lowerBound~upperBound
    });
    super.initState();
  }

  @override
  void dispose() {
    // TODO: implement dispose
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Demo'),
      ),
      body: Center(
        //移动
        child: SlideTransition(
          // position: _controller.drive(Tween(
          //     begin: const Offset(0.0, 0.0), end: const Offset(10.0, 10.0))),
          position: Tween(
                  begin: const Offset(0.0, 0.0), end: const Offset(10.0, 10.0))
              .chain(CurveTween(curve: Curves.elasticInOut))
              .animate(_controller),
          //Tween改变开始和结束
          child: const Icon(
            Icons.refresh,
            size: 100,
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            // _controller.forward(); //转一圈
            _controller.repeat(reverse: true); //重复转
            // _controller.reset(); //回到原来的状态
            // _controller.stop(); //原地停止
          });
        },
        tooltip: 'change',
        child: const Icon(Icons.add),
      ),
    );
  }
}

交错动画

其他动画