1

【笔记】Flutter 的动画

 10 months ago
source link: https://loli.fj.cn/2023/08/17/Flutter%E7%9A%84%E5%8A%A8%E7%94%BB/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Flutter 的动画学习笔记

duration:定义动画持续时间
curve:定义动画类型

Curves.linear:缺省值,线性
Curves.linear:线性

AnimatedList 动画列表

淡入淡出动画

animation:在新增操作时,animation 的值是从 0 到 1;在删除操作时,animation 的值是从 1 到 0

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), // 执行动画的元素
);
}),
),
);
}
}
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:定义动画持续时间

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 动画内边距

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 动画透明度

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 动画定位

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 动画默认文字样式

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 动画切换

  • 当子元素发生任意改变时触发动画
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:缺省值

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:缺省值

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:缺省值

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:缺省值

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:缺省值

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:缺省值

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

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

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,
),
),
);
}
}
添加动画链
  • 通过 chain 方法追加其他方法
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,
),
),
);
}
}

哔哩哔哩 —— 筱筱知晓


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK