如需转载,请注明出处:Flutter学习笔记(36)--经常使用内置动画html
Flutter给咱们提供了不少并且很好用的内置动画,这些动画仅仅须要简单的几行代码就能够实现一些不错的效果,Flutter的动画分为补间动画和基于物理的动画,基于物理的动画咱们先不说。git
补间动画很简单,Android里面也有补间动画,就是给UI设置初始的状态和结束状态,通过咱们定义的一段时间,系统去帮助咱们实现开始到结束的过渡变化,这就是补间动画。github
今天咱们要看的Flutter的内置动画就是补间动画,根据Flutter提供的动画组件,咱们去设置初始、结尾的状态,而且定义一下这个变化过程所须要的时间,再通过系统的处理(其实就是setState())来达到动画的效果。api
接下来咱们会写一下经常使用的内置动画组件,而且提供一下动画效果的gif,方便你们更直观的去理解。app
- AnimatedContainer
看到Container咱们就会知道这是一个带有动画属性的容器组件,这个组件能够定义大小、颜色等属性,那么咱们是否是就能够给这个组件设置初始和结束的大小及颜色的属性值,而后经过系统来帮助咱们来补足中间过程的动画呢?less
答案是能够的,下面看一下demo和动画效果:ide
class _MyHomePageState extends State<MyHomePage> { double _width = 100.0; double _height = 100.0; Color _color = Colors.red; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: AnimatedContainer( width: _width, height: _height, duration: Duration(seconds: 2), color: _color, curve: Curves.bounceInOut, ), floatingActionButton: FloatingActionButton( onPressed: () { setState(() { _width = 300.0; _height = 300.0; _color = Colors.green; }); }, tooltip: 'Increment', child: Icon(Icons.adjust), ), // This trailing comma makes auto-formatting nicer for build methods. ); } }
demo很简单,就是先定义好组件初始的大小和颜色,点击按钮,在按钮事件里面去更改大小和颜色的属性值。这里惟一须要特别说一下就是curve这个属性。函数
curve指的是动画曲线?我开始的时候不理解这个动画曲线是什么意思,后来看了一组图以后,豁然开朗。demo里面curve咱们用的是Curves.bounceInOut。以下:学习
它其实就是一个非线性的动画的变化形式(变化过程)也能够理解为就是一种函数,也不知道这么说你们能不能理解。动画
/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_bounce_in.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_bounce_in_out.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_bounce_out.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_decelerate.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_sine.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_quad.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_cubic.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_quart.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_quint.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_expo.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_circ.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_back.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_out.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_out_sine.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_out_quad.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_out_cubic.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_out_quart.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_out_quint.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_out_expo.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_out_circ.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_in_out_back.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_out.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_out_sine.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_out_quad.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_out_cubic.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_out_quart.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_out_quint.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_out_expo.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_out_circ.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_ease_out_back.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_elastic_in.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_elastic_in_out.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_elastic_out.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_fast_out_slow_in.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_slow_middle.mp4} /// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_linear.mp4}
这里是每一种curve曲线的表现形式,你们能够看看,也能够在demo里面多尝试,或者能够看另外一篇博客,有动画曲线Curves 效果。
-
AnimatedCrossFade
Flutter中文网:一个widget,在两个孩子之间交叉淡入,并同时调整他们的尺寸。
我的说明:CrossFade,故名思意,淡入淡出,AnimatedCrossFade组件包含两个子widget,一个firstChild一个secondChild,这两个组件根据状态(咱们本身定义的一个标识)改变状态,
一个淡入,一个淡出,同时改变大小或颜色等属性。
class _MyHomePageState extends State<MyHomePage> { bool _showFirst = true; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: AnimatedCrossFade( firstChild: Container( width: 100, height: 100, color: Colors.red, alignment: Alignment.center, child: Text('firstChild'), ), secondChild: Container( width: 200, height: 200, color: Colors.green, alignment: Alignment.center, child: Text('secondChild'), ), duration: Duration(seconds: 3), crossFadeState: _showFirst ? CrossFadeState.showFirst : CrossFadeState.showSecond, ), floatingActionButton: FloatingActionButton( onPressed: () { setState(() { _showFirst = false; }); }, tooltip: 'Increment', child: Icon(Icons.adjust), ), // This trailing comma makes auto-formatting nicer for build methods. ); } }
-
Hero
Hero经常使用于页面跳转的过长动画,好比电商App有一个商品列表,列表的每一个item都有一张缩略图,点击会跳转到详情页面,在Flutter中将图片从一个路由飞到另外一个路由称为hero动画,尽管相同的动做有时也称为 共享元素转换。
class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Hero( tag: 'heroTag', child: ClipOval( child: Image.asset( 'images/banner.png', width: 60, height: 60, fit: BoxFit.cover, ), ), ), floatingActionButton: FloatingActionButton( onPressed: () { setState(() { Navigator.push(context, MaterialPageRoute(builder: (_) { return new HeroPage(); })); }); }, tooltip: 'Increment', child: Icon(Icons.adjust), ), // This trailing comma makes auto-formatting nicer for build methods. ); } }
详情页面:
import 'package:flutter/material.dart'; class HeroPage extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'HeroPage', home: Scaffold( appBar: AppBar( title: Text('HeroPage'), ), body: Center( child: GestureDetector( child: Hero( tag: 'heroTag', child: ClipOval( child: Image.asset( 'images/banner.png', width: 300, height: 300, fit: BoxFit.cover, ), ), ), onTap: () { Navigator.pop(context); }, ), ), ), ); } }
注:特别强调一下,为了将两个页面的元素关联起来,hero有个tag标识,先后两个页面的tag标识必须同样,否则的话元素是关联不起来的,也就意味着不会产生hero动画。
1.同级tag不容许相同。
2.先后页面想要有hero动画,tag必须相同。
3.先后关联起来的hero组件,其各自内部的child组件不是必须同样的,就是说前面的hero的子组件能够是image,后面的hero的子组件能够是image之外的其余组件。
-
AnimatedBuilder
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin { Animation<double> _animation; AnimationController _animationController; @override void initState() { _animationController = AnimationController(duration: Duration(seconds: 3), vsync: this); _animation = new Tween(begin: 0.0, end: 200.0).animate(_animationController); _animationController.forward(); super.initState(); } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: AnimatedBuilder( animation: _animation, builder: (BuildContext context, Widget child) { return Center( child: Container( color: Colors.red, width: _animation.value, height: _animation.value, child: child, ), ); }, )); } }
AnimationController:动画控制器(定义动画过程时长)。
Animation:动画变化区间值(也能够说是开始和结束的关键帧值),demo里定义的值为初始0,结束200。
_animation.value:关键帧值是0和200,_animation.value的值为0--200之间连续变化的值(0-1-2-3-...-198-199-200)。
-
DecoratedBoxTransition
Decortated能够给容器添加各类外观装饰,好比增长圆角、阴影等装饰。DecoratedBox的动画版本,能够给它的Decoration不一样属性使用动画
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin { Animation<Decoration> _animation; AnimationController _animationController; @override void initState() { _animationController = AnimationController(duration: Duration(seconds: 3), vsync: this); _animation = DecorationTween( begin: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(0.0)), color: Colors.red), end: BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(30.0)), color: Colors.green)) .animate(_animationController); _animationController.forward(); super.initState(); } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(widget.title)), body: Center( child: DecoratedBoxTransition( decoration: _animation, child: Container( width: 100, height: 100, ), ), ), ); } }
-
FadeTransition
透明度变化动画,由于透明度也是在0-1之间变化的,因此animation就还继续用double类型的就能够了。
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin { Animation<double> _animation; AnimationController _animationController; @override void initState() { _animationController = AnimationController(duration: Duration(seconds: 2), vsync: this); _animation = Tween(begin: 1.0, end: 0.0).animate(_animationController); _animationController.forward(); super.initState(); } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(widget.title)), body: Center( child: FadeTransition( opacity: _animation, child: Container( width: 100, height: 100, decoration: BoxDecoration( color: Colors.red, ), ), ), ), ); } }
- RotationTransition
旋转动画,对widget使用旋转动画 1~360°(Tween(begin: 0.0, end: 1.0))这里的0-1指的是0°-360°
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin { Animation<double> _animation; AnimationController _animationController; @override void initState() { _animationController = AnimationController(duration: Duration(seconds: 2), vsync: this); _animation = Tween(begin: 0.0, end: 1.0).animate(_animationController); _animationController.forward(); super.initState(); } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(widget.title)), body: Center( child: RotationTransition( turns: _animation, child: Container( width: 100, height: 100, decoration: BoxDecoration( color: Colors.red, ), child: Center(child: Text('data')), ), ), ), ); } }
-
ScaleTransition
缩放动画,Tween(begin: 1.0, end: 0.2)指的是原大小的倍数,demo里是由原大小缩小到原来的0.2倍。
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin { Animation<double> _animation; AnimationController _animationController; @override void initState() { _animationController = AnimationController(duration: Duration(seconds: 2), vsync: this); _animation = Tween(begin: 1.0, end: 0.2).animate(_animationController); _animationController.forward(); super.initState(); } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(widget.title)), body: Center( child: ScaleTransition( scale: _animation, child: Container( width: 200, height: 200, decoration: BoxDecoration( color: Colors.red, ), child: Center(child: Text('data')), ), ), ), ); } }
-
SizeTransition
仅一个方向进行缩放
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin { Animation<double> _animation; AnimationController _animationController; @override void initState() { _animationController = AnimationController(duration: Duration(seconds: 2), vsync: this); _animation = Tween(begin: 1.0, end: 0.2).animate(_animationController); _animationController.forward(); super.initState(); } @override void dispose() { _animationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(widget.title)), body: Center( child: SizeTransition( axis: Axis.horizontal, sizeFactor: _animation, child: Center( child: Container( width: 200, height: 200, decoration: BoxDecoration( color: Colors.red, ), child: Center(child: Text('data')), ), ), ), ), ); } }
以上!有任何疑问欢迎留言!