概念
从一个状态平滑过渡到另一个状态
4个核心要素
1.AnimationController:动画控制器,管理时间(电影播放器)
2.Animation:动画值,随时间变化(电影画面)
3.Tween:生成器,创建动画范围(剧本:从哪到哪)
4.Curve:动画曲线,控制动画随时间的变化
AnimationController的常见方法
1.forward():开始播放动画
2.stop():停止动画播放
3.reset():重制动画为初始化状态
4.reverse():反向播放动画,必须正向动画播放完成之后才有效
5.repeat():循环播放动画
6.dispose():销毁动画,释放动画占用资源。
Animation
四种状态值
1.dismissed:动画处于开始状态。
2.forward:动画正在正向执行。
3.reverse:动画正在反向执行。
4.completed:动画处于结束状态。
有两个监听器Listeners和StatusListeners
1.addListener():用于给Animation对象添加帧监听器,每一帧都会被调用,当帧监听器监听到状态发生改变后就会调用setState()来触发视图的重建。
2.addStatusListener():用于给Animation对象添加动画状态改变监听器,动画开始、结束、正向或反向时就会调用状态改变的监听器。
Tween
begin和end的使用技巧
Dart
Tween<double>(begin: 0, end: 1) 定义的是动画的数值范围:
begin:动画开始时的数值
end:动画结束时的数值
1. 0和1的含义
0:通常表示"无"、"开始"、"最小"、"透明"、"隐藏"
1:通常表示"完整"、"结束"、"最大"、"不透明"、"显示"
2.什么时候用0和1
当组件参数本身就是比例时(如opacity、scale、progress)
当需要与其他值相乘计算时
当需要标准化多个动画时
3.什么时候用具体数值
当有明确的物理单位时(像素、角度、颜色)
当需要精确控制时
当直接对应屏幕坐标或尺寸时
4.技巧
透明度:0(透明) → 1(不透明)
缩放: 0(消失) → 1(原大) → >1(放大)
旋转: 0°(开始) → 360°(一圈)
位置: 0(起点) → 100(终点像素)
进度: 0(0%) → 1(100%)
基础动画类tween
Dart
// 数值插值-Tween
Animation<double> sizeAnim = Tween<double>(begin: 0, end: 200)
.animate(_controller);
// 颜色插值-ColorTween
Animation<Color?> colorAnim = ColorTween(
begin: Colors.red,
end: Colors.blue
) .animate(_controller);
// 矩形插值-RectTween
Animation<Rect?> rectAnim = RectTween(
begin: Rect.zero,
end: Rect.fromLTRB(0, 0, 100, 100))
.animate(_controller);
// 边界插值-BorderRadiusTween
Animation<BorderRadius?> radiusAnim = BorderRadiusTween(
begin: BorderRadius.zero,
end: BorderRadius.circular(20))
.animate(_controller);
动画序列类AnimationSequence
Dart
// 创建序列动画:包含3个阶段
_sequenceAnim = TweenSequence<double>([
// 第一阶段:从0到100,使用easeIn曲线
TweenSequenceItem<double>(
tween: Tween<double>(begin: 0, end: 100)
.chain(CurveTween(curve: Curves.easeIn)),
weight: 1.0, // 权重1,占总时长的1/3
),
// 第二阶段:从100到200,使用easeOut曲线
TweenSequenceItem<double>(
tween: Tween<double>(begin: 100, end: 200)
.chain(CurveTween(curve: Curves.easeOut)),
weight: 1.0, // 权重1,占总时长的1/3
),
// 第三阶段:从200回到150,使用bounceOut曲线
TweenSequenceItem<double>(
tween: Tween<double>(begin: 200, end: 150)
.chain(CurveTween(curve: Curves.bounceOut)),
weight: 1.0, // 权重1,占总时长的1/3
),
]).animate(_controller);
组合动画类Interval
Dart
Animation<double> delayedAnim = Tween<double>(begin: 0, end: 1)
.animate(CurvedAnimation(
parent: _controller,
curve: Interval(0.5, 1.0), // 在动画的后半段播放
));
物理动画类SpringSimulation
Dart
final simulation = SpringSimulation(
SpringDescription(
mass: 1,
stiffness: 100,
damping: 10,
),
0.0, // 起始值
1.0, // 目标值
100, // 初始速度
);
_controller.animateWith(simulation);
1.mass质量:默认值通常是1;(0.1~10.0)
值越大 → 惯性越大,动画越"沉重";
值越小 → 响应越快,动画越"轻快"
2.stiffness刚度:弹簧的硬度/弹性系数;(50~1000)
值越大 → 弹簧越硬,动画越快、弹性越强
值越小 → 弹簧越软,动画越慢、弹性越弱
3.stiffness: 100,
damping阻尼:抵抗运动的阻力;(1~50)
值越大 → 阻力越大,动画越快停止(过阻尼)
值越小 → 阻力越小,动画会更多次反弹(欠阻尼)
合适值 → 刚好能平稳停止(临界阻尼)
Curves类定义的动画曲线
基本曲线
Dart
1.linear:匀速动画
2.decelerate:匀减速动画
3.ease:先加速后减速动画
4.easeIn:先快后慢动画
5.easeOut:先慢后快动画
6.easeInOut:先慢,然后加速,最后减速动画
弹性/弹簧效果
Dart
Curves.elasticIn // 弹性进入
Curves.elasticOut // 弹性退出
Curves.elasticInOut // 弹性进出
Curves.bounceIn // 弹跳进入
Curves.bounceOut // 弹跳退出
Curves.bounceInOut // 弹跳进出
其他特殊效果
Dart
Curves.decelerate // 减速
Curves.slowMiddle // 中间慢
Curves.backIn // 后退进入
Curves.backOut // 后退退出
Curves.backInOut // 后退进出
Flutter动画的标准流程
Dart
1.定义动画控制器和动画值。
2.初始化动画控制器,绑定State和设置动画时间。
3.设置动画值的开始值和结束值,然后通过animate绑定动画控制器。
4.在UI中绑定动画控制器
如果需要需要设置时间区间和弹性效果需要animate绑定CurvedAnimation,
用CurvedAnimation绑定动画控制器和设置时间区间和弹性效果
例子:
_fadeAnimation = Tween<double>(begin: 0, end: 1).animate(
CurvedAnimation(
parent: _controller,
curve: Interval(0.0, 0.3, curve: Curves.easeIn),
),
);
//InterVal是一种曲线类型,用于控制动画在指定时间区间内发生,可以让多个动画按顺序或分段执行
// Interval(begin, end) 中的 begin 和 end 指的是时间比例
//比如:begin=0.3:动画在总时间的30%处开始,,end=0.7:动画在总时间的70%处结束
Flutter动画架构层次
Dart
UI组件
↑
动画值 (Animation<double>) //定义具体动画变化(大小,位置,颜色等)
↑
动画控制器 (AnimationController) //控制动画播放,暂停,停止,重置
↑
TickerProvider (vsync) //驱动动画
动画之间的区别
Dart
1.显式动画:
需要手动管理 AnimationController
有明确的控制器
需要自己处理动画状态
示例中的 _controller.forward()、_controller.reverse()
2.隐式动画:
自动管理动画
如 AnimatedContainer、AnimatedOpacity
Flutter 自动处理开始、结束、反转
3.简单动画
单个 Tween + 单个属性
4.组合动画
多个动画的组合
一.隐式动画
效果图

代码实例
Dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<StatefulWidget> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
bool _isExpanded = false; //容器缩放
bool _isRotated = false; //旋转状态
double _opacity = 1.0; //透明度
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('隐式动画')),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 1. AnimatedContainer
GestureDetector(
onTap: () => setState(() => _isExpanded = !_isExpanded), //点击切换状态
child: AnimatedContainer( //AnimatedContainer - 容器动画
duration: Duration(milliseconds: 500), //动画时长
width: _isExpanded ? 300 : 150, //变化范围
height: _isExpanded ? 200 : 100,
decoration: BoxDecoration( //容器风格
color: Colors.blue,
borderRadius: BorderRadius.circular(_isExpanded ? 30 : 10),
),
child: Center(
child: Text(
'点击缩放',
style: TextStyle(color: Colors.white, fontSize: 20),
),
),
),
),
SizedBox(height: 30),
// 2. TweenAnimationBuilder 旋转
GestureDetector(
onTap: () => setState(() => _isRotated = !_isRotated), //点击切换状态
child: TweenAnimationBuilder<double>( //TweenAnimationBuilder - 自定义值动画
duration: Duration(milliseconds: 800), //动画时长
tween: Tween(begin: 0, end: _isRotated ? 360 : 0), //值范围定义:动画的起始和结束值
curve: Curves.easeInOut, //动画曲线
builder: (context, angle, child) { //angle由Flutter框架自动传入
return Transform.rotate( //旋转变换
angle: angle * (3.14159 / 180), //当前角度(弧度)
child: Container(
width: 100,
height: 100,
color: Colors.green,
child: Center(child: Text('旋转')),
),
);
},
),
),
SizedBox(height: 30),
// 3. AnimatedOpacity
GestureDetector(
onTap: () => setState(() => _opacity = _opacity == 1.0 ? 0.3 : 1.0),
child: AnimatedOpacity( //AnimatedOpacity - 透明度动画
duration: Duration(milliseconds: 500),
opacity: _opacity,
child: Container(
width: 150,
height: 100,
color: Colors.orange,
child: Center(child: Text('透明度动画')),
),
),
),
],
),
);
}
}
二.显式动画
基础显式动画
效果图

代码示例
Dart
import 'dart:async';
import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<StatefulWidget> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
late AnimationController _controller; //动画控制器
late Animation<double> _animation; //动画值
@override
void initState(){
super.initState();
//1.创建动画控制器
_controller = AnimationController(
vsync: this,// 绑定到 State(通过 SingleTickerProviderStateMixin)
duration: Duration(seconds: 2),
);
//2.创建动画值(从0到1)
_animation = Tween<double>(begin: 0,end: 1).animate(_controller);
//3.监听动画状态变化
_controller.addStatusListener((status){
if(status == AnimationStatus.completed){
print("动画完成");
}else if(status == AnimationStatus.dismissed){
print("动画重置");
}
});
}
@override
void dispose() {
_controller.dispose(); //释放资源
super.dispose();
}
//===========================开始播放动画=============================
void _startAnimation(){
if(_controller.status == AnimationStatus.completed){
_controller.reverse();//反向播放
}else{
_controller.forward();//正向播放
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('基础显式动画')),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AnimatedBuilder(
animation: _animation,
builder: (context,child){
return Container(
width: 100 + _animation.value * 200, //宽度从100到300
height: 100,
color: Colors.blue.withOpacity(_animation.value),
child: Center(
child: Text(
'${(_animation.value * 100).toInt()}%',
style: TextStyle(color: Colors.white),
),
),
);
}
),
SizedBox(height: 30,),
ElevatedButton(
onPressed: _startAnimation,
child: Text("开始动画"),
),
],
),
);
}
}
使用Curve控制动画曲线
效果图

代码实例
Dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<StatefulWidget> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
late AnimationController _controller; //动画控制器
late Animation<double> _animation; //动画值
final List<String> _title = [ //曲线名称列表
"linear",
"easeIn",
"easeOut",
"easeInOut",
"bounceOut",
"elasticOut"
];
final List<Curve> _curves = [ //动画曲线
Curves.linear, // 线性
Curves.easeIn, // 缓慢开始,加速结束
Curves.easeOut, // 快速开始,缓慢结束
Curves.easeInOut, // 缓慢开始和结束
Curves.bounceOut, // 弹跳效果
Curves.elasticOut,// 弹性效果
];
int _currentCurveIndex = 0; //当前选中的曲线索引
@override
void initState() {
super.initState();
//初始化控制器
_controller = AnimationController(
vsync: this,
duration: Duration(seconds: 2),
);
//初始化动画
_updateAnimation();
}
//动画配置方法
void _updateAnimation() {
_animation = CurvedAnimation(
parent: _controller,
curve: _curves[_currentCurveIndex], //应用当前选中曲线
).drive(Tween<double>(begin: 0, end: 300)); //创建动画值范围
}
//切换曲线的方法
void _changeCurve() {
setState(() {
_currentCurveIndex = (_currentCurveIndex + 1) % _curves.length; //循环切换
_updateAnimation(); //更新动画配置
});
_controller.reset(); //重置动画到开始状态
_controller.forward();//开始播放动画
}
@override
void dispose() {
_controller.dispose(); //释放资源
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('动画曲线示例')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
//动画显示部分
AnimatedBuilder(
animation: _animation, //监听动画值变化
builder: (context, child) {
return Container(
width: _animation.value,//宽度随值变化
height: 100,
color: Colors.pink,
child: Center(
child: Text(
_title[_currentCurveIndex], //显示当前曲线名称
style: TextStyle(color: Colors.white),
),
),
);
},
),
SizedBox(height: 30),
//切换按钮
ElevatedButton(
onPressed: _changeCurve,
child: Text('切换曲线-- ${_title[_currentCurveIndex]}'),
),
],
),
),
);
}
}
动画序列
效果图

代码实例
Dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/physics.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<StatefulWidget> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _sequenceAnim;
late Animation<Color?> _colorAnim;
@override
void initState() {
super.initState();
// 创建动画控制器,时长6秒
_controller = AnimationController(
vsync: this,
duration: const Duration(seconds: 6),
);
// 创建序列动画:包含3个阶段
_sequenceAnim = TweenSequence<double>([
// 第一阶段:从0到100,使用easeIn曲线
TweenSequenceItem<double>(
tween: Tween<double>(begin: 0, end: 100)
.chain(CurveTween(curve: Curves.easeIn)),
weight: 1.0, // 权重1,占总时长的1/3
),
// 第二阶段:从100到200,使用easeOut曲线
TweenSequenceItem<double>(
tween: Tween<double>(begin: 100, end: 200)
.chain(CurveTween(curve: Curves.easeOut)),
weight: 1.0, // 权重1,占总时长的1/3
),
// 第三阶段:从200回到150,使用bounceOut曲线
TweenSequenceItem<double>(
tween: Tween<double>(begin: 200, end: 150)
.chain(CurveTween(curve: Curves.bounceOut)),
weight: 1.0, // 权重1,占总时长的1/3
),
]).animate(_controller);
// 创建颜色动画,与序列动画同步
_colorAnim = ColorTween(
begin: Colors.blue,
end: Colors.red,
).animate(_controller);
// 监听动画状态变化
_controller.addStatusListener((status) {
if (status == AnimationStatus.completed) { //动画在结束位置
Future.delayed(const Duration(seconds: 1), () {
_controller.reverse(); //反向播放
});
} else if (status == AnimationStatus.dismissed) { //动画在开始位置
Future.delayed(const Duration(seconds: 1), () {
_controller.forward(); //正向播放
});
}
});
// 开始动画
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('TweenSequence动画序列示例'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 动画显示的方块
AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Container(
width: _sequenceAnim.value, // 宽度使用序列动画的值
height: _sequenceAnim.value, // 高度使用序列动画的值
color: _colorAnim.value, // 颜色随进度变化
alignment: Alignment.center,
child: Text(
'${_sequenceAnim.value.toInt()}',
style: const TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
);
},
),
const SizedBox(height: 30),
// 动画进度显示
AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Text(
'进度: ${(_controller.value * 100).toStringAsFixed(1)}%\n'
'当前值: ${_sequenceAnim.value.toStringAsFixed(1)}\n'
'阶段: ${_getCurrentStage(_controller.value)}',
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 16),
);
},
),
const SizedBox(height: 30),
// 控制按钮
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
if (_controller.isAnimating) {
_controller.stop();
} else {
_controller.isCompleted
? _controller.reverse()
: _controller.forward();
}
},
child: AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Text(
_controller.isAnimating ? '暂停' : '继续',
);
},
),
),
const SizedBox(width: 20),
ElevatedButton(
onPressed: () => _controller.reset(),
child: const Text('重置'),
),
const SizedBox(width: 20),
ElevatedButton(
onPressed: () => _controller.repeat(),
child: const Text('循环播放'),
),
],
),
const SizedBox(height: 20),
// 动画描述
Container(
padding: const EdgeInsets.all(16),
margin: const EdgeInsets.symmetric(horizontal: 20),
decoration: BoxDecoration(
color: Colors.grey[100],
borderRadius: BorderRadius.circular(10),
),
child: const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'动画序列说明:',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
SizedBox(height: 8),
Text('第1阶段 (0-33%):宽度/高度 0→100,easeIn曲线'),
Text('第2阶段 (34-66%):宽度/高度 100→200,easeOut曲线'),
Text('第3阶段 (67-100%):宽度/高度 200→150,bounceOut曲线'),
SizedBox(height: 8),
Text('颜色:蓝色→红色,随总进度线性变化'),
],
),
),
],
),
),
);
}
// 获取当前动画阶段
String _getCurrentStage(double value) {
if (value < 0.33) return '第1阶段: 0→100 (easeIn)';
if (value < 0.66) return '第2阶段: 100→200 (easeOut)';
return '第3阶段: 200→150 (bounceOut)';
}
}
三.组合动画
基础组合动画
效果图:颜色,大小,都会改变,且伴随旋转

代码实例
Dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/physics.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<StatefulWidget> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _sizeAnimation;
late Animation<double> _rotationAnimation;
late Animation<Color?> _colorAnimation;
@override
void initState(){
super.initState();
//初始化动画控制器
_controller = AnimationController(
vsync: this,
duration: Duration(seconds:2), //动画持续时间
)..repeat(reverse: true); //无限循环播放
//大小动画
_sizeAnimation = Tween<double>(begin:50,end:200).animate(
CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
);
//旋转动画
_rotationAnimation = Tween<double>(begin: 0,end:360).animate(
CurvedAnimation(parent: _controller, curve: Curves.linear),
);
//颜色动画
_colorAnimation = ColorTween(begin: Colors.red,end:Colors.blue,).animate(_controller);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("组合动画"),),
body: Center(
child: AnimatedBuilder(
animation: _controller,
builder: (context,child){
return Transform.rotate(angle: _rotationAnimation.value * (3.14159 / 180 ),
child: Container(
width: _sizeAnimation.value,
height: _sizeAnimation.value,
decoration: BoxDecoration(
color: _colorAnimation.value,
shape: BoxShape.circle,
),
child: Center(child: Text('组合动画',style: TextStyle(color: Colors.white),),),
),
);
}
),
),
);
}
}
交错动画
通过重叠或顺序排列的时间区间来控制多个动画的执行时机。
效果图

交错时间线可视化
时间轴: 0% ────── 20% ────── 40% ────── 60% ────── 80% ────── 100%
动画:
淡入 │─────────────│
上滑 │─────────────│
缩放 │─────────────│
旋转 │─────────────│
效果:
1. 0-20%: 只执行淡入
2. 20-40%:淡入+上滑同时执行
3. 40-60%:上滑+缩放同时执行
4. 60-80%:缩放+旋转同时执行
5. 80-100%:只执行旋转
代码实例
Dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<StatefulWidget> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
late AnimationController _controller; //controller.value 从 0.0 到 1.0(时间进度)
// 定义多个动画
late Animation<double> _fadeAnimation;
late Animation<double> _scaleAnimation;
late Animation<Offset> _slideAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 1500),
);
// 淡入动画(0-500ms)
_fadeAnimation = Tween<double>(begin: 0, end: 1).animate(
CurvedAnimation(
parent: _controller,
curve: Interval(0.0, 0.3, curve: Curves.easeIn),
),
);
// 缩放动画(200-700ms)
_scaleAnimation = Tween<double>(begin: 0.5, end: 1).animate(
CurvedAnimation(
parent: _controller,
curve: Interval(0.2, 0.5, curve: Curves.elasticOut),
),
);
// 滑动动画(400-1200ms)
_slideAnimation = Tween<Offset>(
begin: Offset(0, 1), // 向下一个自身高度 ;优点:无论元素多高,都向下移动一个自身高度
end: Offset.zero,
).animate(
CurvedAnimation(
parent: _controller,
curve: Interval(0.4, 0.8, curve: Curves.fastOutSlowIn),
),
);
}
void _playAnimation() {
if (_controller.status == AnimationStatus.completed) {
_controller.reverse();
} else {
_controller.forward();
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('交错动画')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SlideTransition(
position: _slideAnimation,
child: ScaleTransition(
scale: _scaleAnimation,
child: FadeTransition(
opacity: _fadeAnimation,
child: Container(
width: 200,
height: 200,
color: Colors.green,
child: Center(
child: Text(
'交错动画效果',
style: TextStyle(color: Colors.white, fontSize: 20),
),
),
),
),
),
),
SizedBox(height: 30),
ElevatedButton(
onPressed: _playAnimation,
child: Text('播放动画'),
),
],
),
),
);
}
}
物理动画:弹簧动画
效果图

代码实例
Dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/physics.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<StatefulWidget> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
late AnimationController _controller; //controller.value 从 0.0 到 1.0(时间进度)
SpringDescription _spring = SpringDescription(
mass: 1,//质量
stiffness: 100,//刚度
damping: 2//阻尼
);
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(seconds: 5),
)..addListener(() => setState(() {}));
}
void _startSpringAnimation(double velocity){
final simulation = SpringSimulation(
_spring, //弹簧参数
_controller.value, //起始值
1.0, //目标值
velocity //初始速度
);
_controller.animateWith(simulation);
}
void _reset(){
_controller.reset();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('物理动画')),
body: GestureDetector(
onTap: (){
_startSpringAnimation(1000);
},
onDoubleTap: _reset,
child: Center(
child: Transform.translate(
offset: Offset(0, _controller.value * 200),
child: Container(
width: 100,
height: 100,
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(20)
),
child: Center(
child: Text(
'弹簧动画\n单击开始\n双击重置',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white),
),
),
),
),
),
)
);
}
}