文章目录




Flutter 动画基本流程 :

① 创建动画控制器

② 创建动画

③ 设置值监听器

④ 设置状态监听器

⑤ 布局中使用动画值

⑥ 动画运行






一、创建动画控制器



AnimationController 构造函数参数说明 :

AnimationController(
{double? value, /// 动画的初始值
Duration? duration, /// 动画正向播放持续时间
Duration? reverseDuration, /// 动画逆序播放持续时间
String? debugLabel, /// 调试期间标识动画的标志
double lowerBound: 0.0, /// 动画最小值
double upperBound: 1.0, /// 动画最大值
AnimationBehavior animationBehavior: AnimationBehavior.normal,
/// 上下文的 TickerProvider , 用于防止屏幕外的动画消耗不必要的资源 ,
/// 一般将 StatefulWidget 作为 vsync 值
required TickerProvider vsync}
)



上述参数中 , 只需要设置 ​​required TickerProvider vsync​​​ 参数 与 ​​Duration? duration​​ 参数即可 ;



创建动画控制器代码示例 :

/// 1. 初始化动画控制器
animationController = AnimationController(
// 动画绘制到屏幕外部时, 减少消耗
vsync: this,
// 动画持续时间 2 秒
duration: Duration(seconds: 3),
);






二、创建动画



这里创建 Tween 补间动画 , 设置动画的初始值 0 0 0 , 结束值 300 300 300 , 动画在执行的 3 3 3 秒时间内 ( 动画控制器中指定的动画持续时间 ) , 自动计算出每个时间点的 0 0 0 ~ 300 300 300 之间的动画值 ;

创建动画代码示例 :

/// 2 . 构造 Tween 补间动画 ,
/// 设置动画控制器 AnimationController 给该补间动画
/// 动画的值是正方形组件的宽高
animation = Tween<double>(
begin: 0,
end: 300
).animate(animationController)






三、设置值监听器



调用 Animation 的 addListener 方法 , 可以为动画添加值监听器 ;

简洁用法 :​ 上一行代码表达式必须是 animation, 结尾不能有分号 , 之后可以使用 ​​..addListener​​​ 用法 , 该用法等价于 ​​animation.addListener​​ ;

setState 方法 :​ 动画如果生效, 必须在监听器中调用 setState 方法 , 以便重新调用 build 方法进行布局渲染 , 否则 UI 界面不会刷新 ;



" 设置值监听器 " 代码示例 :

/// 3 . 添加动画值监听器
/// 该用法与 animation.addListener 效果是等价的
/// 这种写法比较简洁
/// 类似于链式调用, 上一行代码表达式必须是 animation, 结尾不能有分号
/// 特别注意 : 动画如果生效, 必须在监听器中调用 setState 方法
..addListener(() {

/// 调用 setState 方法后, 更新相关状态值后, 自动调用 build 方法重构组件界面
setState(() {
// 获取动画执行过程中的值
animationValue = animation.value;
});

})






四、设置状态监听器



调用 Animation 的 addStatusListener方法 , 可以为动画添加值监听器 ;

简洁用法 :​ 上一行代码表达式必须是 animation, 结尾不能有分号 , 之后可以使用 ​​..addStatusListener​​​ 用法 , 该用法等价于 ​​animation.addStatusListener​​ ;

setState 方法 :​ 动画如果生效, 必须在监听器中调用 setState 方法 , 以便重新调用 build 方法进行布局渲染 , 否则 UI 界面不会刷新 ;



" 设置状态监听器 " 代码示例 :

/// 4 . 添加动画状态监听器
/// 设置动画状态监听器
..addStatusListener((status) {
/// 调用 setState 方法后, 更新相关状态值后, 自动调用 build 方法重构组件界面
setState(() {
/// 获取动画状态
animationStatus = status;
});
});






五、布局中使用动画值



在 build 方法中返回的布局组件中 , 使用上述监听器中获取的动画值 animationValue , 该值是 0 0 0 ~ 300 300 300 之间的浮点数 ;

这里使用动画值作为正方形组件的宽高 ;



" 布局中使用动画值 " 代码示例 :

// 动画的主体组件
// 6 . 布局组件中使用动画的值 , 以达到动画效果
Container(
/// 设置距离顶部 20 像素
margin: EdgeInsets.only(top: 50),
height: animationValue,
width: animationValue,
decoration: BoxDecoration(color: Colors.red),
),






六、动画运行



监听 GestureDetector 的 onTap 点击事件 , 点击该组件后 , 调用 ​​animationController.forward()​​ 方法 , 运行动画 ;



代码示例 :

GestureDetector(
// 5 . 点击按钮开启动画
onTap: (){
/// 按钮点击事件
/// 首先将动画初始化
animationController.reset();

/// 正向执行动画, 即从初始值执行到结束值
animationController.forward();

},
child: Container(
alignment: Alignment.center,
color: Colors.green,
height: 50,
child: Text(
// 显示文本
"动画开始",
/// 文字方向 : 从左到右
textDirection: TextDirection.ltr,
),
),
),






七、完整代码示例



完整代码示例 :

import 'package:flutter/material.dart';

void main() {
runApp(AnimationApp());
}

/// 动画示例主界面组件
/// 该组件是有状态的, 因此需要定义 StatefulWidget 组件
class AnimationApp extends StatefulWidget{
@override
_AnimationAppState createState() => _AnimationAppState();
}

/// 为 StatefulWidget 组件创建 State 类
/// 每个 StatefulWidget 都需要一个配套的 State 类
class _AnimationAppState extends State<AnimationApp>
with SingleTickerProviderStateMixin{

/// 动画类
Animation<double> animation;

/// 动画控制器
AnimationController animationController;

/// 动画状态
AnimationStatus animationStatus;

/// 动画值
/// 动画运行过程中, 动画计算出来的值
double animationValue;


@override
void initState() {
super.initState();

/// 1. 初始化动画控制器
animationController = AnimationController(
// 动画绘制到屏幕外部时, 减少消耗
vsync: this,
// 动画持续时间 2 秒
duration: Duration(seconds: 3),
);


/// 2 . 构造 Tween 补间动画 ,
/// 设置动画控制器 AnimationController 给该补间动画
/// 动画的值是正方形组件的宽高
animation = Tween<double>(
begin: 0,
end: 300
).animate(animationController)


/// 3 . 添加动画值监听器
/// 该用法与 animation.addListener 效果是等价的
/// 这种写法比较简洁
/// 类似于链式调用, 上一行代码表达式必须是 animation, 结尾不能有分号
/// 特别注意 : 动画如果生效, 必须在监听器中调用 setState 方法
..addListener(() {

/// 调用 setState 方法后, 更新相关状态值后, 自动调用 build 方法重构组件界面
setState(() {
// 获取动画执行过程中的值
animationValue = animation.value;
});

})

/// 4 . 添加动画状态监听器
/// 设置动画状态监听器
..addStatusListener((status) {
/// 调用 setState 方法后, 更新相关状态值后, 自动调用 build 方法重构组件界面
setState(() {
/// 获取动画状态
animationStatus = status;
});
});

}

/// 该方法与 initState 对应
@override
void dispose() {

/// 释放动画控制器
animationController.dispose();

super.dispose();
}


@override
Widget build(BuildContext context) {

return Container(

/// 设置距离顶部 20 像素
margin: EdgeInsets.only(top: 100),

child: Column(
children: [

GestureDetector(
// 5 . 点击按钮开启动画
onTap: (){
/// 按钮点击事件
/// 首先将动画初始化
animationController.reset();

/// 正向执行动画, 即从初始值执行到结束值
animationController.forward();

},
child: Container(
alignment: Alignment.center,
color: Colors.green,
height: 50,
child: Text(
// 显示文本
"动画开始",
/// 文字方向 : 从左到右
textDirection: TextDirection.ltr,
),
),
),


Text("动画状态 : $animationStatus", textDirection: TextDirection.ltr,),

Text("动画值 : ${animationValue?.round()}", textDirection: TextDirection.ltr,),

// 动画的主体组件
// 6 . 布局组件中使用动画的值 , 以达到动画效果
Container(
/// 设置距离顶部 20 像素
margin: EdgeInsets.only(top: 50),
height: animationValue,
width: animationValue,
decoration: BoxDecoration(color: Colors.red),
),


],
),
);
}

}

运行效果 :

【Flutter】Animation 动画 ( Flutter 动画基本流程 | 创建动画控制器 | 创建动画 | 设置值监听器 | 设置状态监听器 | 布局中使用动画值 | 动画运行 )_flutter






八、相关资源



参考资料 :


重要的专题 :


博客源码下载 :