10天学会flutter DAY10 flutter 玩转 动画与打包
Posted 不爱学习的猪
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了10天学会flutter DAY10 flutter 玩转 动画与打包相关的知识,希望对你有一定的参考价值。
🔥🔥🔥玩转 动画与打包🔥🔥🔥
动画
Flutter中的动画系统基于Animation
对象的,和之前的手势不同,它不是一个Widget,这是因为Animation
对象本身和UI渲染没有任何关系。Animation是一个抽象类,就相当于一个定时器,它用于保存动画的插值和状态,并执行数值的变化。widget可以在build
函数中读取Animation
对象的当前值, 并且可以监听动画的状态改变。
AnimationController
AnimationController用于控制动画,它包含动画的启动forward()
、停止stop()
、反向播放 reverse()
等方法。AnimationController会在动画的每一帧,就会生成一个新的值。默认情况下,AnimationController在给定的时间段内线性的生成从0.0到1.0(默认区间)的数字。
AnimationController controller = AnimationController(
duration: const Duration(milliseconds: 2000), //动画时间
lowerBound: 10.0, //生成数字的区间
upperBound: 20.0, //10.0 - 20.0
vsync: this //TickerProvider 动画驱动器提供者
);
Ticker
Ticker的作用是添加屏幕刷新回调,每次屏幕刷新都会调用TickerCallback
。使用Ticker来驱动动画会防止屏幕外动画(动画的UI不在当前屏幕时,如锁屏时)消耗不必要的资源。因为Flutter中屏幕刷新时会通知Ticker,锁屏后屏幕会停止刷新,所以Ticker就不会再触发。最简单的做法为将SingleTickerProviderStateMixin
添加到State的定义中。
import 'package:flutter/material.dart';
void main() => runApp(AnimationApp());
class AnimationApp extends StatelessWidget
@override
Widget build(BuildContext context)
return MaterialApp(
title: "animation",
home: Scaffold(
appBar: AppBar(
title: Text('animation'),
),
body: AnimWidget(),
),
);
// 动画是有状态的
class AnimWidget extends StatefulWidget
@override
State<StatefulWidget> createState()
return _AnimWidgetState();
class _AnimWidgetState extends State<AnimWidget>
with SingleTickerProviderStateMixin
AnimationController controller;
bool forward = true;
@override
void initState()
super.initState();
controller = AnimationController(
// 动画的时长
duration: Duration(milliseconds: 2000),
lowerBound: 10.0,
upperBound: 100.0,
// 提供 vsync 最简单的方式,就是直接混入 SingleTickerProviderStateMixin
// 如果有多个AnimationController,则使用TickerProviderStateMixin。
vsync: this,
);
//状态修改监听
controller
..addStatusListener((AnimationStatus status)
debugPrint("状态:$status");
)
..addListener(()
setState(() => );
);
debugPrint("controller.value:$controller.value");
@override
Widget build(BuildContext context)
return Column(
children: <Widget>[
Container(
width: controller.value,
height: controller.value,
color: Colors.blue,
),
RaisedButton(
child: Text("播放"),
onPressed: ()
if (forward)
controller.forward();
else
controller.reverse();
forward = !forward;
,
),
RaisedButton(
child: Text("停止"),
onPressed: ()
controller.stop();
,
)
],
);
动画状态监听:在forword结束之后状态为completed。在reverse结束之后状态为dismissed
Tween
默认情况下,AnimationController
对象值为:double类型,范围是0.0到1.0 。如果我们需要不同的范围或不同的数据类型,则可以使用Tween来配置动画以生成不同的范围或数据类型的值。要使用Tween对象,需要调用其animate()
方法,然后传入一个控制器对象,同时动画过程中产生的数值由Tween
的lerp
方法决定。
import 'package:flutter/material.dart';
void main() => runApp(AnimationApp());
class AnimationApp extends StatelessWidget
@override
Widget build(BuildContext context)
return MaterialApp(
title: "animation",
home: Scaffold(
appBar: AppBar(
title: Text('animation'),
),
body: AnimWidget(),
),
);
// 动画是有状态的
class AnimWidget extends StatefulWidget
@override
State<StatefulWidget> createState()
return _AnimWidgetState();
class _AnimWidgetState extends State<AnimWidget>
with SingleTickerProviderStateMixin
AnimationController controller;
bool forward = true;
Tween<Color> tween;
@override
void initState()
super.initState();
controller = AnimationController(
// 动画的时长
duration: Duration(milliseconds: 2000),
// 提供 vsync 最简单的方式,就是直接继承 SingleTickerProviderStateMixin
vsync: this,
);
//使用Color
tween = ColorTween(begin: Colors.blue, end: Colors.yellow);
//添加动画值修改监听
tween.animate(controller)..addListener(() => setState(() ));
@override
Widget build(BuildContext context)
return Column(
children: <Widget>[
Container(
width: 100,
height: 100,
//获取动画当前值
color: tween.evaluate(controller),
),
RaisedButton(
child: Text("播放"),
onPressed: ()
if (forward)
controller.forward();
else
controller.reverse();
forward = !forward;
,
),
RaisedButton(
child: Text("停止"),
onPressed: ()
controller.stop();
,
)
],
);
Curve
动画过程默认是线性的(匀速),如果需要非线形的,比如:加速的或者先加速后减速等。Flutter中可以通过Curve(曲线)来描述动画过程。
import 'package:flutter/material.dart';
void main() => runApp(AnimationApp());
class AnimationApp extends StatelessWidget
@override
Widget build(BuildContext context)
return MaterialApp(
title: "animation",
home: Scaffold(
appBar: AppBar(
title: Text('animation'),
),
body: AnimWidget(),
),
);
// 动画是有状态的
class AnimWidget extends StatefulWidget
@override
State<StatefulWidget> createState()
return _AnimWidgetState();
class _AnimWidgetState extends State<AnimWidget>
with SingleTickerProviderStateMixin
AnimationController controller;
Animation<double> animation;
bool forward = true;
@override
void initState()
super.initState();
controller = AnimationController(
// 动画的时长
duration: Duration(milliseconds: 2000),
// 提供 vsync 最简单的方式,就是直接继承 SingleTickerProviderStateMixin
vsync: this,
);
//弹性
animation = CurvedAnimation(parent: controller, curve: Curves.bounceIn);
//使用Color
animation = Tween(begin: 10.0, end: 100.0).animate(animation)
..addListener(()
setState(() => );
);
@override
Widget build(BuildContext context)
return Column(
children: <Widget>[
Container(
//不需要转换
width: animation.value,
height: animation.value,
//获取动画当前值
color: Colors.blue,
),
RaisedButton(
child: Text("播放"),
onPressed: ()
if (forward)
controller.forward();
else
controller.reverse();
forward = !forward;
,
),
RaisedButton(
child: Text("停止"),
onPressed: ()
controller.stop();
,
)
],
);
AnimatedWidget
通过上面的学习我们能够感受到Animation
对象本身和UI渲染没有任何关系。而通过addListener()
和setState()
来更新UI这一步其实是通用的,如果每个动画中都加这么一句是比较繁琐的。AnimatedWidget类封装了调用setState()
的细节,简单来说就是自动调用setState()
。
Flutter中已经封装了很多动画,比如对widget进行缩放,可以直接使用ScaleTransition
import 'package:flutter/material.dart';
void main() => runApp(AnimationApp());
class AnimationApp extends StatelessWidget
@override
Widget build(BuildContext context)
return MaterialApp(
title: "animation",
home: Scaffold(
appBar: AppBar(
title: Text('animation'),
),
body: AnimWidget(),
),
);
// 动画是有状态的
class AnimWidget extends StatefulWidget
@override
State<StatefulWidget> createState()
return _AnimWidgetState();
class _AnimWidgetState extends State<AnimWidget>
with SingleTickerProviderStateMixin
AnimationController controller;
Animation<double> animation;
bool forward = true;
@override
void initState()
super.initState();
controller = AnimationController(
// 动画的时长
duration: Duration(milliseconds: 2000),
// 提供 vsync 最简单的方式,就是直接继承 SingleTickerProviderStateMixin
vsync: this,
);
//弹性
animation = CurvedAnimation(parent: controller, curve: Curves.bounceIn);
//使用Color
animation = Tween(begin: 10.0, end: 100.0).animate(animation);
@override
Widget build(BuildContext context)
return Column(
children: <Widget>[
ScaleTransition(
child: Container(
width: 100,
height: 100,
color: Colors.blue,
),
scale: controller,
),
RaisedButton(
child: Text("播放"),
onPressed: ()
if (forward)
controller.forward();
else
controller.reverse();
forward = !forward;
,
),
RaisedButton(
child: Text("停止"),
onPressed: ()
controller.stop();
,
)
],
);
Hero动画
Hero动画就是在路由切换时,有一个共享的Widget可以在新旧路由间切换,由于共享的Widget在新旧路由页面上的位置、外观可能有所差异,所以在路由切换时会逐渐过渡,这样就会产生一个Hero动画。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return new MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(
title: Text("主页"),
),
body: Route1()),
);
// 路由A
class Route1 extends StatelessWidget
@override
Widget build(BuildContext context)
return Container(
alignment: Alignment.topCenter,
child: InkWell(
child: Hero(
tag: "avatar", //唯一标记,前后两个路由页Hero的tag必须相同
child: CircleAvatar(
backgroundImage: AssetImage(
"assets/banner.jpeg",
),
),
),
onTap: ()
Navigator.push(context, MaterialPageRoute(builder: (_)
return Route2();
));
,
),
);
class Route2 extends StatelessWidget
@override
Widget build(BuildContext context)
return Center(
child: Hero(
tag: "avatar", //唯一标记,前后两个路由页Hero的tag必须相同
child: Image.asset("assets/banner.jpeg")),
);
组合动画
有些时候我们可能会需要执行一个动画序列执行一些复杂的动画。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return new MaterialApp(
title: 'Flutter Demo',
home: Route(),
);
class Route extends StatefulWidget
@override
State<StatefulWidget> createState()
return RouteState();
class RouteState extends State<Route> with SingleTickerProviderStateMixin
Animation<Color> color;
Animation<double> width;
AnimationController controller;
@override
void initState()
super.initState();
controller = AnimationController(
// 动画的时长
duration: Duration(milliseconds: 2000),
// 提供 vsync 最简单的方式,就是直接继承 SingleTickerProviderStateMixin
vsync: this,
);
//高度动画
width = Tween<double>(
begin: 100.0,
end: 300.0,
).animate(
CurvedAnimation(
parent: controller,
curve: Interval(
//间隔,前60%的动画时间 1200ms执行高度变化
0.0, 0.6,
),
),
);
color = ColorTween(
begin: Colors.green,
end: Colors.red,
).animate(
CurvedAnimation(
parent: controlle以上是关于10天学会flutter DAY10 flutter 玩转 动画与打包的主要内容,如果未能解决你的问题,请参考以下文章