前言
Flutter的动画学习笔记
隐式动画
duration
:定义动画持续时间
curve
:定义动画类型
Curves.linear
:缺省值,线性
Curves.linear
:线性
AnimatedList动画列表
淡入淡出动画
animation
:在新增操作时,animation
的值是从0到1;在删除操作时,animation
的值是从1到0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| import 'dart:async';
import 'package:flutter/material.dart';
void main() { runApp(const MaterialApp( home: App(), )); }
class App extends StatefulWidget { const App({super.key});
@override State<App> createState() => _AppState(); }
class _AppState extends State<App> { final _globalKey = GlobalKey<AnimatedListState>();
List<String> list = ["1", "2"];
bool lock = false;
Widget _buildItem(index) { return ListTile( title: Text(list[index]), trailing: IconButton( icon: const Icon(Icons.delete), onPressed: () { _deleteItem(index); }, ), ); }
_deleteItem(index) { if (lock) { return; } lock = true; _globalKey.currentState!.removeItem(index, (context, animation) { var removeItem = _buildItem(index); list.removeAt(index); return FadeTransition( opacity: animation, child: removeItem, ); }); Timer.periodic(const Duration(milliseconds: 500), (timer) { lock = false; timer.cancel(); }); }
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("文本内容"), ), floatingActionButton: FloatingActionButton( onPressed: () { list.add("0"); _globalKey.currentState!.insertItem(list.length - 1); }, child: const Icon(Icons.add), ), body: AnimatedList( key: _globalKey, initialItemCount: list.length, itemBuilder: ((context, index, animation) { return FadeTransition( opacity: animation, child: _buildItem(index), ); }), ), ); } }
|
缩放动画
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| import 'dart:async';
import 'package:flutter/material.dart';
void main() { runApp(const MaterialApp( home: App(), )); }
class App extends StatefulWidget { const App({super.key});
@override State<App> createState() => _AppState(); }
class _AppState extends State<App> { final _globalKey = GlobalKey<AnimatedListState>();
List<String> list = ["1", "2"];
bool lock = false;
Widget _buildItem(index) { return ListTile( title: Text(list[index]), trailing: IconButton( icon: const Icon(Icons.delete), onPressed: () { _deleteItem(index); }, ), ); }
_deleteItem(index) { if (lock) { return; } lock = true; _globalKey.currentState!.removeItem(index, (context, animation) { var removeItem = _buildItem(index); list.removeAt(index); return ScaleTransition( scale: animation, child: removeItem, ); }); Timer.periodic(const Duration(milliseconds: 500), (timer) { lock = false; timer.cancel(); }); }
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("文本内容"), ), floatingActionButton: FloatingActionButton( onPressed: () { list.add("0"); _globalKey.currentState!.insertItem(list.length - 1); }, child: const Icon(Icons.add), ), body: AnimatedList( key: _globalKey, initialItemCount: list.length, itemBuilder: ((context, index, animation) { return ScaleTransition( scale: animation, child: _buildItem(index), ); }), ), ); } }
|
AnimatedContainer动画容器
duration
:定义动画持续时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| import 'dart:async';
import 'package:flutter/material.dart';
void main() { runApp(const MaterialApp( home: App(), )); }
class App extends StatefulWidget { const App({super.key});
@override State<App> createState() => _AppState(); }
class _AppState extends State<App> { bool flag = true;
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("文本内容"), ), floatingActionButton: FloatingActionButton( onPressed: () { setState(() { flag = !flag; }); }, child: const Icon(Icons.add), ), body: AnimatedContainer( duration: const Duration( seconds: 1, ), width: flag ? 200 : 400, height: flag ? 200 : 400, color: Colors.blue, ), ); } }
|
AnimatedPadding动画内边距
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| import 'dart:async';
import 'package:flutter/material.dart';
void main() { runApp(const MaterialApp( home: App(), )); }
class App extends StatefulWidget { const App({super.key});
@override State<App> createState() => _AppState(); }
class _AppState extends State<App> { bool flag = true;
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("文本内容"), ), floatingActionButton: FloatingActionButton( onPressed: () { setState(() { flag = !flag; }); }, child: const Icon(Icons.add), ), body: AnimatedPadding( padding: EdgeInsets.fromLTRB(0, flag ? 0 : 200, 0, 0), curve: Curves.linear, duration: const Duration( seconds: 1, ), child: Container( width: 200, height: 200, color: Colors.blue, ), ), ); } }
|
AnimatedOpacity动画透明度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| import 'dart:async';
import 'package:flutter/material.dart';
void main() { runApp(const MaterialApp( home: App(), )); }
class App extends StatefulWidget { const App({super.key});
@override State<App> createState() => _AppState(); }
class _AppState extends State<App> { bool flag = true;
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("文本内容"), ), floatingActionButton: FloatingActionButton( onPressed: () { setState(() { flag = !flag; }); }, child: const Icon(Icons.add), ), body: AnimatedOpacity( opacity: flag ? 1 : 0.5, duration: const Duration( seconds: 1, ), child: Container( width: 200, height: 200, color: Colors.blue, ), ), ); } }
|
AnimatedPositioned动画定位
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| import 'dart:async';
import 'package:flutter/material.dart';
void main() { runApp(const MaterialApp( home: App(), )); }
class App extends StatefulWidget { const App({super.key});
@override State<App> createState() => _AppState(); }
class _AppState extends State<App> { bool flag = true;
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("文本内容"), ), floatingActionButton: FloatingActionButton( onPressed: () { setState(() { flag = !flag; }); }, child: const Icon(Icons.add), ), body: Stack( children: [ AnimatedPositioned( top: flag ? 0 : 200, duration: const Duration( seconds: 1, ), child: Container( width: 200, height: 200, color: Colors.blue, ), ) ], ), ); } }
|
AnimatedDefaultTextStyle动画默认文字样式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| import 'dart:async';
import 'package:flutter/material.dart';
void main() { runApp(const MaterialApp( home: App(), )); }
class App extends StatefulWidget { const App({super.key});
@override State<App> createState() => _AppState(); }
class _AppState extends State<App> { bool flag = true;
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("文本内容"), ), floatingActionButton: FloatingActionButton( onPressed: () { setState(() { flag = !flag; }); }, child: const Icon(Icons.add), ), body: AnimatedDefaultTextStyle( style: TextStyle( color: Colors.blue, fontSize: flag ? 20 : 40, ), duration: const Duration( seconds: 1, ), child: const Text("文本内容"), ), ); } }
|
AnimatedSwitcher动画切换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| import 'dart:async';
import 'package:flutter/material.dart';
void main() { runApp(const MaterialApp( home: App(), )); }
class App extends StatefulWidget { const App({super.key});
@override State<App> createState() => _AppState(); }
class _AppState extends State<App> { bool flag = true;
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("文本内容"), ), floatingActionButton: FloatingActionButton( onPressed: () { setState(() { flag = !flag; }); }, child: const Icon(Icons.add), ), body: AnimatedSwitcher( duration: const Duration( seconds: 1, ), child: flag ? const Text("文本内容1") : const Text("文本内容2"), ), ); } }
|
显式动画
vsync
:配置程序的刷新率与手机保持一致
_animationController.forward()
:正向运动一次
_animationController.reverse()
:逆向运动一次,需要在正向运动后再执行
_animationController.repeat()
:正向运动无限循环
_animationController.repeat(reverse: true)
:正向运动然后逆向运动无限循环
_animationController.stop()
:停止运动
_animationController.reset()
:重置
旋转动画
通过构造方法配置controller
lowerBound
:动画初始值
0
:缺省值
upperBound
:动画终止值
1
:缺省值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| import 'dart:async';
import 'package:flutter/material.dart';
void main() { runApp(const MaterialApp( home: App(), )); }
class App extends StatefulWidget { const App({super.key});
@override State<App> createState() => _AppState(); }
class _AppState extends State<App> with SingleTickerProviderStateMixin { late AnimationController _animationController; bool flag = true;
@override void initState() { super.initState(); _animationController = AnimationController( vsync: this, duration: const Duration(seconds: 1), lowerBound: 0, upperBound: 1, ); }
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("文本内容"), ), floatingActionButton: FloatingActionButton( onPressed: () { flag ? _animationController.forward() : _animationController.reverse(); flag = !flag; }, child: const Icon(Icons.add), ), body: RotationTransition( turns: _animationController, child: Container( width: 200, height: 200, color: Colors.blue, ), ), ); } }
|
通过drive方法配置controller
begin
:动画初始值
0
:缺省值
end
:动画终止值
1
:缺省值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| import 'dart:async';
import 'package:flutter/material.dart';
void main() { runApp(const MaterialApp( home: App(), )); }
class App extends StatefulWidget { const App({super.key});
@override State<App> createState() => _AppState(); }
class _AppState extends State<App> with SingleTickerProviderStateMixin { late AnimationController _animationController; bool flag = true;
@override void initState() { super.initState(); _animationController = AnimationController( vsync: this, duration: const Duration(seconds: 1), ); }
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("文本内容"), ), floatingActionButton: FloatingActionButton( onPressed: () { flag ? _animationController.forward() : _animationController.reverse(); flag = !flag; }, child: const Icon(Icons.add), ), body: RotationTransition( turns: _animationController.drive(Tween(begin: 0, end: 1)), child: Container( width: 200, height: 200, color: Colors.blue, ), ), ); } }
|
显示/隐藏动画
通过构造方法配置controller
lowerBound
:动画初始值
0
:缺省值
upperBound
:动画终止值
1
:缺省值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| import 'dart:async';
import 'package:flutter/material.dart';
void main() { runApp(const MaterialApp( home: App(), )); }
class App extends StatefulWidget { const App({super.key});
@override State<App> createState() => _AppState(); }
class _AppState extends State<App> with SingleTickerProviderStateMixin { late AnimationController _animationController; bool flag = true;
@override void initState() { super.initState(); _animationController = AnimationController( vsync: this, duration: const Duration(seconds: 1), lowerBound: 0, upperBound: 1, ); }
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("文本内容"), ), floatingActionButton: FloatingActionButton( onPressed: () { flag ? _animationController.forward() : _animationController.reverse(); flag = !flag; }, child: const Icon(Icons.add), ), body: FadeTransition( opacity: _animationController, child: Container( width: 200, height: 200, color: Colors.blue, ), ), ); } }
|
通过drive方法配置controller
begin
:动画初始值
0
:缺省值
end
:动画终止值
1
:缺省值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| import 'dart:async';
import 'package:flutter/material.dart';
void main() { runApp(const MaterialApp( home: App(), )); }
class App extends StatefulWidget { const App({super.key});
@override State<App> createState() => _AppState(); }
class _AppState extends State<App> with SingleTickerProviderStateMixin { late AnimationController _animationController; bool flag = true;
@override void initState() { super.initState(); _animationController = AnimationController( vsync: this, duration: const Duration(seconds: 1), ); }
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("文本内容"), ), floatingActionButton: FloatingActionButton( onPressed: () { flag ? _animationController.forward() : _animationController.reverse(); flag = !flag; }, child: const Icon(Icons.add), ), body: FadeTransition( opacity: _animationController.drive(Tween(begin: 0, end: 1)), child: Container( width: 200, height: 200, color: Colors.blue, ), ), ); } }
|
放大/缩小动画
通过构造方法配置controller
lowerBound
:动画初始值
0
:缺省值
upperBound
:动画终止值
1
:缺省值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| import 'dart:async';
import 'package:flutter/material.dart';
void main() { runApp(const MaterialApp( home: App(), )); }
class App extends StatefulWidget { const App({super.key});
@override State<App> createState() => _AppState(); }
class _AppState extends State<App> with SingleTickerProviderStateMixin { late AnimationController _animationController; bool flag = true;
@override void initState() { super.initState(); _animationController = AnimationController( vsync: this, duration: const Duration(seconds: 1), lowerBound: 0, upperBound: 1, ); }
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("文本内容"), ), floatingActionButton: FloatingActionButton( onPressed: () { flag ? _animationController.forward() : _animationController.reverse(); flag = !flag; }, child: const Icon(Icons.add), ), body: ScaleTransition( scale: _animationController, child: Container( width: 200, height: 200, color: Colors.blue, ), ), ); } }
|
通过drive方法配置controller
begin
:动画初始值
0
:缺省值
end
:动画终止值
1
:缺省值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| import 'dart:async';
import 'package:flutter/material.dart';
void main() { runApp(const MaterialApp( home: App(), )); }
class App extends StatefulWidget { const App({super.key});
@override State<App> createState() => _AppState(); }
class _AppState extends State<App> with SingleTickerProviderStateMixin { late AnimationController _animationController; bool flag = true;
@override void initState() { super.initState(); _animationController = AnimationController( vsync: this, duration: const Duration(seconds: 1), ); }
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("文本内容"), ), floatingActionButton: FloatingActionButton( onPressed: () { flag ? _animationController.forward() : _animationController.reverse(); flag = !flag; }, child: const Icon(Icons.add), ), body: ScaleTransition( scale: _animationController.drive(Tween(begin: 0, end: 1)), child: Container( width: 200, height: 200, color: Colors.blue, ), ), ); } }
|
位移动画
通过drive方法配置controller
begin
:动画初始位置
1.0
:表示1 * width
0.5
:表示0.5 * height
end
:动画终止位置
0.5
:表示0.5 * width
1.0
:表示1 * height
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| import 'dart:async';
import 'package:flutter/material.dart';
void main() { runApp(const MaterialApp( home: App(), )); }
class App extends StatefulWidget { const App({super.key});
@override State<App> createState() => _AppState(); }
class _AppState extends State<App> with SingleTickerProviderStateMixin { late AnimationController _animationController; bool flag = true;
@override void initState() { super.initState(); _animationController = AnimationController( vsync: this, duration: const Duration(seconds: 1), ); }
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("文本内容"), ), floatingActionButton: FloatingActionButton( onPressed: () { flag ? _animationController.forward() : _animationController.reverse(); flag = !flag; }, child: const Icon(Icons.add), ), body: SlideTransition( position: _animationController .drive(Tween(begin: const Offset(1.0, 0.5), end: const Offset(0.5, 1.0))), child: Container( width: 200, height: 200, color: Colors.blue, ), ), ); } }
|
通过Tween类配置controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| import 'dart:async';
import 'package:flutter/material.dart';
void main() { runApp(const MaterialApp( home: App(), )); }
class App extends StatefulWidget { const App({super.key});
@override State<App> createState() => _AppState(); }
class _AppState extends State<App> with SingleTickerProviderStateMixin { late AnimationController _animationController; bool flag = true;
@override void initState() { super.initState(); _animationController = AnimationController( vsync: this, duration: const Duration(seconds: 1), ); }
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("文本内容"), ), floatingActionButton: FloatingActionButton( onPressed: () { flag ? _animationController.forward() : _animationController.reverse(); flag = !flag; }, child: const Icon(Icons.add), ), body: SlideTransition( position: Tween(begin: const Offset(1, 0.5), end: const Offset(0.5, 1)) .animate(_animationController), child: Container( width: 200, height: 200, color: Colors.blue, ), ), ); } }
|
添加动画链
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| import 'dart:async';
import 'package:flutter/material.dart';
void main() { runApp(const MaterialApp( home: App(), )); }
class App extends StatefulWidget { const App({super.key});
@override State<App> createState() => _AppState(); }
class _AppState extends State<App> with SingleTickerProviderStateMixin { late AnimationController _animationController; bool flag = true;
@override void initState() { super.initState(); _animationController = AnimationController( vsync: this, duration: const Duration(seconds: 1), ); }
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("文本内容"), ), floatingActionButton: FloatingActionButton( onPressed: () { flag ? _animationController.forward() : _animationController.reverse(); flag = !flag; }, child: const Icon(Icons.add), ), body: SlideTransition( position: Tween(begin: const Offset(1, 0.5), end: const Offset(0.5, 1)) .chain(CurveTween(curve: Curves.bounceInOut)) .chain(CurveTween(curve: const Interval(0, 1))) .animate(_animationController), child: Container( width: 200, height: 200, color: Colors.blue, ), ), ); } }
|
完成
参考文献
哔哩哔哩——筱筱知晓