无论何时构建应用动画在设计用户体验方面都起着至关重要的作用。人们倾向于喜欢流畅且设计精美的应用程序。 Flutter包提供了多种方法来在我们的应用程序中创建和使用动画。我们将讨论用于处理动画的内置Flutter小部件。
如流程图所示,在Flutter处理动画的框架提供了不同容量和实现的小部件。所有动画小部件中存在的基本属性是Duration和Curve 。持续时间是小部件动画的时间,曲线定义对象动画的方式和从开始到结束的方式(动画从开始到结束的流程)。 flutter内置的动画小部件可以分为两大类。
隐式小部件
这些是flutter提供的最简单的小部件。这些小部件无需开发人员做太多工作即可实现。这些是非常基本的动画技术,因此它们没有很多可供更改的选项。它们具有不连续的单向动画。隐式小部件又可以分为两类
- AnimatedXYZ :这里的XYZ是可用于动画的特定小部件。这些是Flutter可用的基本小部件的动画版本。以下是现有 XYZ 小部件的一些隐式 AnimatedXYZ。
- 对齐 → 动画对齐
- 容器 → 动画容器
- DefaultTextStyle → AnimatedDefaultTextStyle
- 填充 → AnimatedPadding
- 定位 → 动画定位
- TweenAnimationBuilder :这些小部件将给定的小部件从初始值 ( Tween.begin ) 动画到最终值 ( Tween.end )。此小部件可用于为简单动画制作自定义小部件。它接受一个 builder 属性,该属性根据其参数中提供的值构建动画。我们还可以在onEnd回调的帮助下提供动画完成时需要执行的操作。
显式小部件
这些小部件对动画小部件提供更精细的控制。它们具有控制小部件的重复和移动的属性。这些小部件需要一个 AnimationController 来实现它们提供的精细控制。这个控制器可以在initState和dispose中定义 状态 为了更好的使用。显式小部件可以归类为
- XYZTransition :这里的XYZ是一个特定的小部件,可用作 Transition。这些是内置过渡,可提供对隐式动画的更多控制。它们可以被认为是AnimatedXYZ小部件的扩展。一些可用的显式XYZTransition是:
- 大小转换
- 淡入淡出
- 对齐过渡
- 旋转过渡
- 定位转换
- 装饰框过渡
- AnimatedBuilder/ AnimatedWidget :当预定义的XYZTransition中没有可用的小部件时,我们可以使用AnimatedBuilder / AnimatedWidget 。它们适用于我们想要显式动画的自定义小部件。如果我们可以在同一个小部件中定义动画,那么我们可以使用 AnimatedBuilder 否则,如果我们定义一个新的小部件,我们可以使用 Animated Widget 扩展定义的小部件。
现在我们已经介绍了内置动画小部件的基本定义。我们将一一查看每个示例。
我们将设置应用程序。首先,我们将在根目录中创建图像目录并将两个图像添加为bird.png和 下面提供了hypno.png
在pubspec.yaml中,在assets 下添加以下几行,然后单击 Pub get 以使用图像
assets:
- images/ #Add
现在已经添加了资源,我们将定义 lib 目录的内容。我们将创建四个新的dart文件作为animation_xyz。dart,吐温动画。dart,xyz_transition。 dart和 builder_animation。除了主要的dart。dart。
主要的。dart有以下代码
Dart
import 'package:flutter/material.dart';
import 'builder_animation.dart';
import 'xyz_transition.dart';
import 'tween_animation.dart';
import 'animated_xyz.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Animation Demo',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: Home(),
);
}
}
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 4,
child: Scaffold(
// define appbar here
appBar: AppBar(
// add tabs to the app
bottom: TabBar(
tabs: [
Tab(text: 'Ani..XYZ'),
Tab(text: 'Tween'),
Tab(text: 'XYZTra..'),
Tab(text: 'Builder'),
],
),
title: Text('GeeksforGeeks'),
),
body: TabBarView(
// animations
children: [
AnimatedXYZ(),
TweenAnimation(),
XYZTransition(),
BuilderAnimation(),
],
),
),
);
}
}
Dart
import 'package:flutter/material.dart';
class AnimatedXYZ extends StatefulWidget {
@override
_AnimatedXYZState createState() => _AnimatedXYZState();
}
// building the container class
class _AnimatedXYZState extends State {
bool _toggle = true;
@override
Widget build(BuildContext context) {
return SafeArea(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.all(20),
child: Text(
'AnimatedContainer',
style: TextStyle(fontSize: 20),
),
),
// using the AnimatedContainer widget
AnimatedContainer(
decoration: BoxDecoration(
color: _toggle == true
? Colors.blueAccent
: Colors.deepPurpleAccent,
borderRadius: BorderRadius.all(Radius.circular(8)),
),
curve: Curves.easeInOutBack,
duration: Duration(seconds: 1),
height: _toggle == true ? 100 : 400,
width: _toggle == true ? 100 : 200,
),
SizedBox(
height: 20,
),
RaisedButton(
onPressed: () {
setState(() {
_toggle = !_toggle;
});
},
child: Text('Animate'),
)
],
),
),
);
}
}
Dart
import 'package:flutter/material.dart';
class TweenAnimation extends StatefulWidget {
@override
_TweenAnimationState createState() => _TweenAnimationState();
}
class _TweenAnimationState extends State {
Color c1 = Colors.white;
Color c2 = Colors.yellow;
@override
Widget build(BuildContext context) {
return SafeArea(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'TweenAnimation',
style: TextStyle(fontSize: 20),
),
SizedBox(
height: 10,
),
// Using TweenAnimationBuilder
TweenAnimationBuilder(
tween: ColorTween(begin: c1, end: c2),
duration: Duration(seconds: 1),
builder: (_, Color color, __) {
return ColorFiltered(
// image assets
child: Image.asset(
'images/bird.png',
height: 180,
),
colorFilter: ColorFilter.mode(color, BlendMode.modulate),
);
},
),
SizedBox(
height: 20,
),
// button
RaisedButton(
onPressed: () {
setState(() {
c1 = c1 == Colors.white ? Colors.yellow : Colors.white;
c2 = c2 == Colors.yellow ? Colors.white : Colors.yellow;
});
},
child: Text('Change Color'),
)
],
),
),
);
}
}
Dart
import 'package:flutter/material.dart';
class XYZTransition extends StatefulWidget {
@override
_XYZTransitionState createState() => _XYZTransitionState();
}
class _XYZTransitionState extends State
with SingleTickerProviderStateMixin {
AnimationController _animationController;
@override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: Duration(seconds: 3),
)..repeat();
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'RotationalTransition',
style: TextStyle(fontSize: 20),
),
SizedBox(
height: 10,
),
// assign action to gestures
GestureDetector(
onTap: () {
_animationController.isAnimating
? _animationController.stop()
: _animationController.repeat();
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// defining the animation type
RotationTransition(
child: Image.asset('images/hypno.png',
height: 150, width: 150),
alignment: Alignment.center,
turns: _animationController,
),
SizedBox(
height: 20,
),
Text('Tap to STOP/ START')
],
),
),
),
),
],
),
),
);
}
}
Dart
import 'package:flutter/material.dart';
class BuilderAnimation extends StatefulWidget {
@override
_BuilderAnimationState createState() => _BuilderAnimationState();
}
class _BuilderAnimationState extends State
with TickerProviderStateMixin {
Animation _starAnimation;
AnimationController _starAnimationController;
bool toggle = false;
// animation controller
@override
void initState() {
super.initState();
_starAnimationController =
AnimationController(vsync: this, duration: Duration(milliseconds: 500));
_starAnimation = Tween(begin: 140.0, end: 160.0).animate(CurvedAnimation(
curve: Curves.elasticInOut, parent: _starAnimationController));
_starAnimationController.addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
_starAnimationController.repeat();
}
});
}
@override
void dispose() {
super.dispose();
_starAnimationController?.dispose();
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'AnimatedBuilder',
style: TextStyle(fontSize: 20),
),
SizedBox(
height: 10,
),
// animated container
// goes as a child
Container(
height: 200,
width: 200,
child: AnimatedBuilder(
animation: _starAnimationController,
builder: (context, child) {
return Center(
child: Container(
child: Center(
child: Icon(
Icons.audiotrack,
color: Colors.orangeAccent,
size: _starAnimation.value,
),
),
),
);
},
),
),
SizedBox(
height: 10,
),
// button
RaisedButton(
child: Text('START/ STOP'),
onPressed: () {
toggle = !toggle;
toggle == true
? _starAnimationController.forward()
: _starAnimationController.stop();
},
),
],
),
);
}
}
在这里,我们制作了一个包含应用栏的 Scaffold,除此之外,应用栏还有一个Tabbar ,用于显示不同动画类型的不同屏幕。
默认情况下,主屏幕显示了我们在 animation_xyz 中定义的 AnimatedXYZ 小部件。dart文件。这显示了我们已经讨论过的第一种类型的隐式小部件。该文件具有以下代码
Dart
import 'package:flutter/material.dart';
class AnimatedXYZ extends StatefulWidget {
@override
_AnimatedXYZState createState() => _AnimatedXYZState();
}
// building the container class
class _AnimatedXYZState extends State {
bool _toggle = true;
@override
Widget build(BuildContext context) {
return SafeArea(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.all(20),
child: Text(
'AnimatedContainer',
style: TextStyle(fontSize: 20),
),
),
// using the AnimatedContainer widget
AnimatedContainer(
decoration: BoxDecoration(
color: _toggle == true
? Colors.blueAccent
: Colors.deepPurpleAccent,
borderRadius: BorderRadius.all(Radius.circular(8)),
),
curve: Curves.easeInOutBack,
duration: Duration(seconds: 1),
height: _toggle == true ? 100 : 400,
width: _toggle == true ? 100 : 200,
),
SizedBox(
height: 20,
),
RaisedButton(
onPressed: () {
setState(() {
_toggle = !_toggle;
});
},
child: Text('Animate'),
)
],
),
),
);
}
}
该文件有一个包含不同小部件的 Column 和一个AnimatedContainer ,除了正常功能外,还定义了曲线和持续时间。当按下按钮时,容器的大小和颜色会发生变化,如下所示:
在下一个屏幕中,我们在tween_animation 中制作了一个 tween 动画。dart文件。在这个动画中,我们有一张鸟的图片,按下按钮会改变鸟的颜色。该文件具有以下代码
Dart
import 'package:flutter/material.dart';
class TweenAnimation extends StatefulWidget {
@override
_TweenAnimationState createState() => _TweenAnimationState();
}
class _TweenAnimationState extends State {
Color c1 = Colors.white;
Color c2 = Colors.yellow;
@override
Widget build(BuildContext context) {
return SafeArea(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'TweenAnimation',
style: TextStyle(fontSize: 20),
),
SizedBox(
height: 10,
),
// Using TweenAnimationBuilder
TweenAnimationBuilder(
tween: ColorTween(begin: c1, end: c2),
duration: Duration(seconds: 1),
builder: (_, Color color, __) {
return ColorFiltered(
// image assets
child: Image.asset(
'images/bird.png',
height: 180,
),
colorFilter: ColorFilter.mode(color, BlendMode.modulate),
);
},
),
SizedBox(
height: 20,
),
// button
RaisedButton(
onPressed: () {
setState(() {
c1 = c1 == Colors.white ? Colors.yellow : Colors.white;
c2 = c2 == Colors.yellow ? Colors.white : Colors.yellow;
});
},
child: Text('Change Color'),
)
],
),
),
);
}
}
在这个文件中,我们简单地定义了一个包含不同小部件的列,除此之外还有一个TweenAnimationBuilder ,它接受补间的类型(这里我们使用了ColorTween )和动画的持续时间。它还有一个 builder 属性,用于构建根据补间提供的小部件。
现在我们已经完成了隐式动画。我们将在接下来的两个屏幕中定义显式动画。显式动画小部件提供了对如何管理动画的更多手动控制。
第三个屏幕显示了RotationTransition的示例。代码如下
Dart
import 'package:flutter/material.dart';
class XYZTransition extends StatefulWidget {
@override
_XYZTransitionState createState() => _XYZTransitionState();
}
class _XYZTransitionState extends State
with SingleTickerProviderStateMixin {
AnimationController _animationController;
@override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: Duration(seconds: 3),
)..repeat();
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'RotationalTransition',
style: TextStyle(fontSize: 20),
),
SizedBox(
height: 10,
),
// assign action to gestures
GestureDetector(
onTap: () {
_animationController.isAnimating
? _animationController.stop()
: _animationController.repeat();
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// defining the animation type
RotationTransition(
child: Image.asset('images/hypno.png',
height: 150, width: 150),
alignment: Alignment.center,
turns: _animationController,
),
SizedBox(
height: 20,
),
Text('Tap to STOP/ START')
],
),
),
),
),
],
),
),
);
}
}
显式小部件为我们提供了更多的手动控制。要访问这些控件,我们需要有一个控制器。所以我们为此定义了一个AnimationController对象。我们需要在构建屏幕时初始化动画,并在移动到另一个屏幕时处理它。这里我们使用RotationTransition无限旋转给定的图像。可以通过点击屏幕上提到的图像来停止/重新启动旋转。过渡接受AnimationController对象作为轮次。我们已经定义在initState 中一旦完成就重复动画。
上面说的显式动画在预定义的 XYZTransition 上工作,但是为了在我们的自定义对象上工作,我们可以使用AnimationBuilder来构建我们自己的动画。代码如下
Dart
import 'package:flutter/material.dart';
class BuilderAnimation extends StatefulWidget {
@override
_BuilderAnimationState createState() => _BuilderAnimationState();
}
class _BuilderAnimationState extends State
with TickerProviderStateMixin {
Animation _starAnimation;
AnimationController _starAnimationController;
bool toggle = false;
// animation controller
@override
void initState() {
super.initState();
_starAnimationController =
AnimationController(vsync: this, duration: Duration(milliseconds: 500));
_starAnimation = Tween(begin: 140.0, end: 160.0).animate(CurvedAnimation(
curve: Curves.elasticInOut, parent: _starAnimationController));
_starAnimationController.addStatusListener((AnimationStatus status) {
if (status == AnimationStatus.completed) {
_starAnimationController.repeat();
}
});
}
@override
void dispose() {
super.dispose();
_starAnimationController?.dispose();
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'AnimatedBuilder',
style: TextStyle(fontSize: 20),
),
SizedBox(
height: 10,
),
// animated container
// goes as a child
Container(
height: 200,
width: 200,
child: AnimatedBuilder(
animation: _starAnimationController,
builder: (context, child) {
return Center(
child: Container(
child: Center(
child: Icon(
Icons.audiotrack,
color: Colors.orangeAccent,
size: _starAnimation.value,
),
),
),
);
},
),
),
SizedBox(
height: 10,
),
// button
RaisedButton(
child: Text('START/ STOP'),
onPressed: () {
toggle = !toggle;
toggle == true
? _starAnimationController.forward()
: _starAnimationController.stop();
},
),
],
),
);
}
}
这个小部件显示了一个反复增长的音乐曲目图标。大多数细节与上面定义的显式XYZTransition保持相同。但是在这里我们必须传递一个带有孩子和上下文的构建器。在这里,我们必须将控制器传递给AnimatedBuilder的 animation 属性。 Button 用于启动和停止动画。
所有动画屏幕的输出: