🔥 本文由 程序喵正在路上 原创,CSDN首发!
💖 系列专栏:Flutter学习
🌠 首发时间:2024年5月29日
🦋 欢迎关注🖱点赞👍收藏🌟留言🐾
目录
- 简介
- RotationTransition组件
- FadeTransition组件
- ScaleTransition组件
- SlideTransition组件
- AnimatedIcon组件
简介
常见的显式动画有 RotationTransition、FadeTransition、ScaleTransition、SlideTransition、AnimatedIcon。在显示动画中开发者需要创建一个 AnimationController,通过 AnimationController 来控制动画的开始、暂停、重置、跳转、倒播等。
RotationTransition组件
RotationTransition 组件是 Flutter 中的一个动画组件,用于在子组件进行旋转动画。它可以根据指定的旋转角度来对子组件进行旋转,并且可以在动画执行过程中实时更新旋转角度以创建平滑的动画效果。
要使用 RotationTransition 组件,你需要提供一个 Animation<double> 对象作为其参数,该动画对象控制着旋转的角度。通常,你可以使用 Flutter 提供的动画控制器(如AnimationController)来创建一个动画对象,并在控制器的值范围内更新角度值。
以下是 RotationTransition 组件的基本属性:
-  turns: 一个 Animation<double>对象,控制旋转的角度。可以通过Tween<double>来创建这个动画对象,也可以使用动画控制器(如AnimationController)。
-  alignment: 一个 AlignmentGeometry 对象,表示旋转的中心点位置,默认为 Alignment.center,即子组件的中心点。
-  child: 要进行旋转动画的子组件。 
AnimationController 普通用法:
import 'package:flutter/material.dart';
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const HomePage(),
    );
  }
}
class HomePage extends StatefulWidget {
  const HomePage({super.key});
  
  State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      /*Vsync 机制可以理解为是显卡与显示器的通信桥梁,显卡在渲染每一帧之前会等待垂
      直同步信号,只有显示器完成了一次刷新时,发出垂直同步信号,显卡才会渲染下一帧,
      确保刷新率和帧率保持同步,以达到供需平衡的效果,防止卡顿现象。 */
      duration: const Duration(seconds: 1),
    );
  }
  
  void dispose() {
    super.dispose();
    _controller.dispose();
  }
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('RotationTransition'),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          RotationTransition(
            turns: _controller,
            child: const FlutterLogo(
              size: 100,
            ),
          ),
          const SizedBox(height: 40),
          Padding(
            padding: const EdgeInsets.fromLTRB(10, 0, 0, 0),
            child: Wrap(
              spacing: 10,
              alignment: WrapAlignment.center,
              children: [
                ElevatedButton(
                  onPressed: () {
                    _controller.forward(); //正序播放一次
                  },
                  child: const Text("Forward"),
                ),
                ElevatedButton(
                    onPressed: () {
                      _controller.reverse(); //倒序播放一次
                    },
                    child: const Text("Reverse")),
                ElevatedButton(
                    onPressed: () {
                      _controller.stop(); //停止播放
                    },
                    child: const Text("Stop")),
                ElevatedButton(
                    onPressed: () {
                      _controller.reset(); //重置
                    },
                    child: const Text("rest")),
                ElevatedButton(
                    onPressed: () {
                      _controller.repeat(); //重复播放
                    },
                    child: const Text("repeat"))
              ],
            ),
          ),
        ],
      ),
    );
  }
}

lowerBound、upperBound:
AnimationController 用于控制动画,它包含动画的启动 forward() 、停止 stop() 、反向播放 reverse() 等方法。 AnimationController 会在动画的每一帧,就会生成一个新的值。默认情况下, AnimationController 在给定的时间段内线性的生成从 0.0 到 1.0(默认区间)的数字 ,我们也可以通过 lowerbound 和 upperBound 来修改 AnimationController 生成数字的区间。
将前面程序的 initState 方法修改一下:
void initState() {
  super.initState();
  _controller = AnimationController(
    vsync: this,
    /*Vsync 机制可以理解为是显卡与显示器的通信桥梁,显卡在渲染每一帧之前会等待垂
    直同步信号,只有显示器完成了一次刷新时,发出垂直同步信号,显卡才会渲染下一帧,
    确保刷新率和帧率保持同步,以达到供需平衡的效果,防止卡顿现象。 */
    duration: const Duration(seconds: 1),
    lowerBound: 3, //第三圈转到第六圈
    upperBound: 6,
  );
  _controller.addListener(() {
    print(_controller.value);
  });
}
设置了 lowerBound 和 upperBound 后,AnimationController 的值就会在它们这个区间中变化,我们可以看到运行后,_controller 就会在 3 到 6 这个区间变化:

FadeTransition组件
FadeTransition 组件是 Flutter 中的一个动画组件,用于在子组件进行透明度渐变动画。它可以根据指定的透明度值来对子组件进行渐变动画,并且可以在动画执行过程中实时更新透明度值以创建平滑的动画效果。
我们将前面程序中的 RotationTransition 换成 FadeTransition,再将 _controller 赋值给它的参数 opacity 即可:
FadeTransition(
  opacity: _controller,
  child: const FlutterLogo(
    size: 100,
  ),
),
记得将刚刚 lowerBound、upperBound 去掉,如果要设置 lowerBound、upperBound,不能大于1,因为透明度在大于 1 后都是一样的。
ScaleTransition组件
ScaleTransition 组件是 Flutter 中的一个动画组件,用于在子组件进行缩放动画。它可以根据指定的缩放比例来对子组件进行缩放动画,并且可以在动画执行过程中实时更新缩放比例以创建平滑的动画效果。
AnimationController 控制动画:
import 'package:flutter/material.dart';
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const HomePage(),
    );
  }
}
class HomePage extends StatefulWidget {
  const HomePage({super.key});
  
  State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      /*Vsync 机制可以理解为是显卡与显示器的通信桥梁,显卡在渲染每一帧之前会等待垂
      直同步信号,只有显示器完成了一次刷新时,发出垂直同步信号,显卡才会渲染下一帧,
      确保刷新率和帧率保持同步,以达到供需平衡的效果,防止卡顿现象。 */
      duration: const Duration(seconds: 1),
    );
    _controller.addListener(() {
      print(_controller.value);
    });
  }
  
  void dispose() {
    super.dispose();
    _controller.dispose();
  }
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('ScaleTransition'),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          ScaleTransition(
            scale: _controller,
            child: const FlutterLogo(size: 100),
          ),
          const SizedBox(height: 40),
          Padding(
            padding: const EdgeInsets.fromLTRB(10, 0, 0, 0),
            child: Wrap(
              spacing: 10,
              alignment: WrapAlignment.center,
              children: [
                ElevatedButton(
                  onPressed: () {
                    _controller.forward(); //正序播放一次
                  },
                  child: const Text("Forward"),
                ),
                ElevatedButton(
                    onPressed: () {
                      _controller.reverse(); //倒序播放一次
                    },
                    child: const Text("Reverse")),
                ElevatedButton(
                    onPressed: () {
                      _controller.stop(); //停止播放
                    },
                    child: const Text("Stop")),
                ElevatedButton(
                    onPressed: () {
                      _controller.reset(); //重置
                    },
                    child: const Text("rest")),
                ElevatedButton(
                    onPressed: () {
                      _controller.repeat(); //重复播放
                    },
                    child: const Text("repeat"))
              ],
            ),
          ),
        ],
      ),
    );
  }
}
AnimationController 结合 Tween 控制动画:
默认情况下, AnimationController 对象值的范围是 [0.0,1.0]。如果我们需要构建 UI 的动画值在不同的范围或不同的数据类型,则可以使用 Tween 来添加映射以生成不同的范围或数据类型的值。
import 'package:flutter/material.dart';
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const HomePage(),
    );
  }
}
class HomePage extends StatefulWidget {
  const HomePage({super.key});
  
  State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      /*Vsync 机制可以理解为是显卡与显示器的通信桥梁,显卡在渲染每一帧之前会等待垂
      直同步信号,只有显示器完成了一次刷新时,发出垂直同步信号,显卡才会渲染下一帧,
      确保刷新率和帧率保持同步,以达到供需平衡的效果,防止卡顿现象。 */
      duration: const Duration(seconds: 1),
    );
    _controller.addListener(() {
      print(_controller.value);
    });
  }
  
  void dispose() {
    super.dispose();
    _controller.dispose();
  }
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('ScaleTransition'),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          ScaleTransition(
            scale: _controller.drive(Tween(begin: 1, end: 2)),
            child: const FlutterLogo(size: 100),
          ),
          const SizedBox(height: 40),
          Padding(
            padding: const EdgeInsets.fromLTRB(10, 0, 0, 0),
            child: Wrap(
              spacing: 10,
              alignment: WrapAlignment.center,
              children: [
                ElevatedButton(
                  onPressed: () {
                    _controller.forward(); //正序播放一次
                  },
                  child: const Text("Forward"),
                ),
                ElevatedButton(
                    onPressed: () {
                      _controller.reverse(); //倒序播放一次
                    },
                    child: const Text("Reverse")),
                ElevatedButton(
                    onPressed: () {
                      _controller.stop(); //停止播放
                    },
                    child: const Text("Stop")),
                ElevatedButton(
                    onPressed: () {
                      _controller.reset(); //重置
                    },
                    child: const Text("rest")),
                ElevatedButton(
                    onPressed: () {
                      _controller.repeat(); //重复播放
                    },
                    child: const Text("repeat"))
              ],
            ),
          ),
        ],
      ),
    );
  }
}
SlideTransition组件
这是一个负责平移的显示动画组件,使用时需要通过 position 属性传入一个 Animated 表示位移程度,通常借助 Tween 实现。
_controller.drive驱动动画:
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const HomePage(),
    );
  }
}
class HomePage extends StatefulWidget {
  const HomePage({super.key});
  
  State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      /*Vsync 机制可以理解为是显卡与显示器的通信桥梁,显卡在渲染每一帧之前会等待垂
      直同步信号,只有显示器完成了一次刷新时,发出垂直同步信号,显卡才会渲染下一帧,
      确保刷新率和帧率保持同步,以达到供需平衡的效果,防止卡顿现象。 */
      duration: const Duration(seconds: 1),
    );
    _controller.addListener(() {
      print(_controller.value);
    });
  }
  
  void dispose() {
    super.dispose();
    _controller.dispose();
  }
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('SlideTransition'),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          SlideTransition(
            position: _controller.drive(
              Tween(
                begin: const Offset(0, 0),
                end: const Offset(1.2, 0), //表示实际的位置为向右移动自身宽度的1.2倍
              ),
            ),
            child: const FlutterLogo(size: 100),
          ),
          const SizedBox(height: 40),
          Padding(
            padding: const EdgeInsets.fromLTRB(10, 0, 0, 0),
            child: Wrap(
              spacing: 10,
              alignment: WrapAlignment.center,
              children: [
                ElevatedButton(
                  onPressed: () {
                    _controller.forward(); //正序播放一次
                  },
                  child: const Text("Forward"),
                ),
                ElevatedButton(
                    onPressed: () {
                      _controller.reverse(); //倒序播放一次
                    },
                    child: const Text("Reverse")),
                ElevatedButton(
                    onPressed: () {
                      _controller.stop(); //停止播放
                    },
                    child: const Text("Stop")),
                ElevatedButton(
                    onPressed: () {
                      _controller.reset(); //重置
                    },
                    child: const Text("rest")),
                ElevatedButton(
                    onPressed: () {
                      _controller.repeat(); //重复播放
                    },
                    child: const Text("repeat"))
              ],
            ),
          ),
        ],
      ),
    );
  }
}
Tween.animate 驱动动画:
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const HomePage(),
    );
  }
}
class HomePage extends StatefulWidget {
  const HomePage({super.key});
  
  State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      /*Vsync 机制可以理解为是显卡与显示器的通信桥梁,显卡在渲染每一帧之前会等待垂
      直同步信号,只有显示器完成了一次刷新时,发出垂直同步信号,显卡才会渲染下一帧,
      确保刷新率和帧率保持同步,以达到供需平衡的效果,防止卡顿现象。 */
      duration: const Duration(seconds: 1),
    );
    _controller.addListener(() {
      print(_controller.value);
    });
  }
  
  void dispose() {
    super.dispose();
    _controller.dispose();
  }
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('SlideTransition'),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          SlideTransition(
            position: Tween(
              begin: const Offset(0, 0),
              end: const Offset(1.2, 0), //表示实际的位置为向右移动自身宽度的1.2倍
            ).animate(_controller),
            child: const FlutterLogo(size: 100),
          ),
          const SizedBox(height: 40),
          Padding(
            padding: const EdgeInsets.fromLTRB(10, 0, 0, 0),
            child: Wrap(
              spacing: 10,
              alignment: WrapAlignment.center,
              children: [
                ElevatedButton(
                  onPressed: () {
                    _controller.forward(); //正序播放一次
                  },
                  child: const Text("Forward"),
                ),
                ElevatedButton(
                    onPressed: () {
                      _controller.reverse(); //倒序播放一次
                    },
                    child: const Text("Reverse")),
                ElevatedButton(
                    onPressed: () {
                      _controller.stop(); //停止播放
                    },
                    child: const Text("Stop")),
                ElevatedButton(
                    onPressed: () {
                      _controller.reset(); //重置
                    },
                    child: const Text("rest")),
                ElevatedButton(
                    onPressed: () {
                      _controller.repeat(); //重复播放
                    },
                    child: const Text("repeat"))
              ],
            ),
          ),
        ],
      ),
    );
  }
}
链式操作修改动画效果:
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const HomePage(),
    );
  }
}
class HomePage extends StatefulWidget {
  const HomePage({super.key});
  
  State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      /*Vsync 机制可以理解为是显卡与显示器的通信桥梁,显卡在渲染每一帧之前会等待垂
      直同步信号,只有显示器完成了一次刷新时,发出垂直同步信号,显卡才会渲染下一帧,
      确保刷新率和帧率保持同步,以达到供需平衡的效果,防止卡顿现象。 */
      duration: const Duration(seconds: 1),
    );
    _controller.addListener(() {
      print(_controller.value);
    });
  }
  
  void dispose() {
    super.dispose();
    _controller.dispose();
  }
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('SlideTransition'),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          SlideTransition(
            position: Tween(
              begin: const Offset(0, -1),
              end: const Offset(0, 3),
            ).chain(CurveTween(curve: Curves.bounceInOut)).animate(_controller),
            child: const FlutterLogo(size: 100),
          ),
          const SizedBox(height: 40),
          Padding(
            padding: const EdgeInsets.fromLTRB(10, 0, 0, 0),
            child: Wrap(
              spacing: 10,
              alignment: WrapAlignment.center,
              children: [
                ElevatedButton(
                  onPressed: () {
                    _controller.forward(); //正序播放一次
                  },
                  child: const Text("Forward"),
                ),
                ElevatedButton(
                    onPressed: () {
                      _controller.reverse(); //倒序播放一次
                    },
                    child: const Text("Reverse")),
                ElevatedButton(
                    onPressed: () {
                      _controller.stop(); //停止播放
                    },
                    child: const Text("Stop")),
                ElevatedButton(
                    onPressed: () {
                      _controller.reset(); //重置
                    },
                    child: const Text("rest")),
                ElevatedButton(
                    onPressed: () {
                      _controller.repeat(); //重复播放
                    },
                    child: const Text("repeat"))
              ],
            ),
          ),
        ],
      ),
    );
  }
}
链式操作修改动动画执行时间:
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const HomePage(),
    );
  }
}
class HomePage extends StatefulWidget {
  const HomePage({super.key});
  
  State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      /*Vsync 机制可以理解为是显卡与显示器的通信桥梁,显卡在渲染每一帧之前会等待垂
      直同步信号,只有显示器完成了一次刷新时,发出垂直同步信号,显卡才会渲染下一帧,
      确保刷新率和帧率保持同步,以达到供需平衡的效果,防止卡顿现象。 */
      duration: const Duration(seconds: 1),
    );
    _controller.addListener(() {
      print(_controller.value);
    });
  }
  
  void dispose() {
    super.dispose();
    _controller.dispose();
  }
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('SlideTransition'),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          SlideTransition(
            position: Tween(
              begin: const Offset(0, -1),
              end: const Offset(0, 3),
            )
                .chain(CurveTween(curve: Curves.bounceInOut))
                .chain(
                    CurveTween(curve: const Interval(0.8, 1))) //在最后20%的时间内完成动画
                .animate(_controller),
            child: const FlutterLogo(size: 100),
          ),
          const SizedBox(height: 40),
          Padding(
            padding: const EdgeInsets.fromLTRB(10, 0, 0, 0),
            child: Wrap(
              spacing: 10,
              alignment: WrapAlignment.center,
              children: [
                ElevatedButton(
                  onPressed: () {
                    _controller.forward(); //正序播放一次
                  },
                  child: const Text("Forward"),
                ),
                ElevatedButton(
                    onPressed: () {
                      _controller.reverse(); //倒序播放一次
                    },
                    child: const Text("Reverse")),
                ElevatedButton(
                    onPressed: () {
                      _controller.stop(); //停止播放
                    },
                    child: const Text("Stop")),
                ElevatedButton(
                    onPressed: () {
                      _controller.reset(); //重置
                    },
                    child: const Text("rest")),
                ElevatedButton(
                    onPressed: () {
                      _controller.repeat(); //重复播放
                    },
                    child: const Text("repeat"))
              ],
            ),
          ),
        ],
      ),
    );
  }
}
AnimatedIcon组件
AnimatedIcon 顾名思义,是一个用于提供动画图标的组件,它的名字虽然是以 Animated 开头,但是他是一个显式动画组件,需要通过 progress 属性传入动画控制器,另外需要由 Icon 属性传入动画图标数据。
import 'package:flutter/material.dart';
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const HomePage(),
    );
  }
}
class HomePage extends StatefulWidget {
  const HomePage({super.key});
  
  State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  
  void initState() {
    super.initState();
    _controller =
        AnimationController(vsync: this, duration: const Duration(seconds: 1));
    _controller.addListener(() {
      print(_controller.value);
    });
  }
  
  void dispose() {
    super.dispose();
    _controller.dispose();
  }
  void _toggleAnimation() {
    if (_controller.status == AnimationStatus.completed) {
      _controller.reverse();
    } else {
      _controller.forward();
    }
  }
  
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: _toggleAnimation,
        child: const Icon(Icons.refresh),
      ),
      appBar: AppBar(
        title: const Text('AnimatedIcon'),
      ),
      body: Center(
        child: AnimatedIcon(
          icon: AnimatedIcons.close_menu,
          progress: _controller,
          size: 40,
        ),
      ),
    );
  }
}
点击浮动按钮后,图标会在关闭和菜单之间变换。



















