动画¶
内置的全自动隐式动画控件¶
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),
),
);
}
}