flutter-常用基础动画
前言
flutter
开发中难免会碰到一些动画操作,且使用率最高的动画基本上都是基础动画,本篇文章主要讲解一些常用的基础动画的使用
ps
:如果下面的基础动画不太满足要求,那么可以采用自定义的方式,其他地方应该有,动画,即动起来的画面,必要的时候,我们可以配合定时器(requestAnimationFrame
)更新视图,也能实现我们的动画效果,就是效果可能不是那么理想,一般情况下基础动画也够用了
动画
常用的基础动画主要分为隐式动画
、显式动画
ps
:使用时需要注意属性更新时会对布局的影响,合理选择布局,避免因为加入动画造成不一样的效果
隐式动画
我们更改某些组件属性的同时,会自动触发组件隐藏的属性动画,因此此类动画被称为隐式动画
,其在其他平台也应该常听到,使用很方便,但无法阻止动画的暂停和继续
常见的隐式动画控件有:AnimatedPositioned
、AnimatedContainer
、AnimatedRotation
、AnimatedScale
、AnimatedOpacity
更新缩放比例 AnimatedScale
double scale = 1;
AnimatedScale(
duration: const Duration(seconds: 2),
scale: scale,
child: Container(
color: Colors.green,
width: 80,
height: 80,
child: TextButton(
onPressed: () {
if (scale > 1) {
setState(() {
scale = 1;
});
}else {
setState(() {
scale = 2;
});
}
},
child: const Text(
'缩放动画',
style: TextStyle(color: Colors.white),
),
),
),
),
更新透明度 AnimatedOpacity
double opacity = 1;
AnimatedOpacity(
duration: const Duration(seconds: 2),
opacity: opacity,
child: Container(
color: Colors.green,
width: 100,
height: 100,
child: TextButton(
onPressed: () {
if (opacity < 1) {
setState(() {
opacity = 1;
});
}else {
setState(() {
opacity = 0.1;
});
}
},
child: const Text(
'缩放动画',
style: TextStyle(color: Colors.white),
),
),
),
),
旋转 AnimatedRotation
旋转参数比较特殊,与其说特殊不如说反常,平常的都是填写角度、弧度等,这里的是填写百分比
,且为占用一圈的百分比
,例如:1 则为顺时针 360°,半圈就是 0.5
double turns = 0; //旋转角度占一圈的百分比
AnimatedRotation(
//旋转占一圈的百分比,360°就是1,半圈就是 0.5,很奇怪是吧,哈哈,公式是这样的😂
//即:旋转 90°,就是 1/4 圈,即 0.25圈
turns: turns, //旋转占一圈的百分比
duration: const Duration(seconds: 2),
child: Container(
color: Colors.green,
width: 100,
height: 100,
child: TextButton(
onPressed: () {
if (turns > 0) {
setState(() {
turns = 0;
});
} else {
setState(() {
//旋转 90°,就是 1/4 圈,即 0.25圈
turns = 0.25;
});
}
},
child: const Text(
'旋转动画',
style: TextStyle(color: Colors.white),
),
),
),
),
更新位置等组合动画
通过上面也可以看到,隐式动画组件基本上和普通组件一样,只不过前面加上了 Animated
,因此我们可以像更新普通组件一样使用它们,同时他们也支持同时更新多个属性,即形成组合动画
double top = 0;
double left = 0;
double width = 80;
double height = 80;
Color color = Colors.green;
//如果打开Animated开头会发现很多类似组件,例如:Padding等,这里面Container也改变了颜色等属性,也都支持
//根据名字对应基础组件就知道动画是干什么的,很简单,就不多介绍了
AnimatedPositioned(
duration: const Duration(seconds: 2),
curve: Curves.easeInOut,
left: left,
top: top,
child: AnimatedContainer(
duration: const Duration(seconds: 2),
curve: Curves.easeInOut,
color: color,
width: width,
height: height,
child: TextButton(
onPressed: () {
if (left > 0) {
setState(() {
color = Colors.green;
left = 0;
top = 0;
width = 80;
height = 80;
});
} else {
setState(() {
color = Colors.yellow;
left = 160;
top = 400;
width = 160;
height = 160;
});
}
},
child: const Text(
'位移大小动画',
style: TextStyle(color: Colors.white),
),
),
),
),
显式动画
显式动画,是根据 Animation
相关动画功能模块形成的动画,支持暂停和继续,可以更好的控制动画的周期变化
AnimationController
:动画控制器,可以控制方向,暂停,指定到某个值等,详细的可以点击去查看,需要继承 SingleTickerProviderStateMixin
Animation<T>
:动画事件,用于更新动画某个属性
更新缩放
class _ScaleTransitionWidgetState extends State<ScaleTransitionWidget> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
//控制动画
_controller = AnimationController(vsync: this, duration: const Duration(seconds: 1));
//设置补间
_animation = Tween<double>(
begin: 1,
end: 4,
).animate(_controller);
//可以设置补间动画动画的动画特性或者运动曲线
// .animate(
// CurvedAnimation(parent: _controller, curve: Curves.easeIn),
// );
//正向执行动画
_controller.forward();
//反向执行动画
_controller.reverse();
//停止动画
_controller.stop();
//动画是否执行完毕
_controller.isCompleted;
}
//直接更新缩放的显式动画组件
ScaleTransition(
scale: _animation,
child: Container(
color: Colors.green,
width: 80,
height: 80,
child: TextButton(
onPressed: () {
if (_controller.isCompleted) {
_controller.reverse();
}else {
_controller.forward();
}
},
child: const Text(
'缩放动画',
style: TextStyle(color: Colors.white),
),
),
),
),
更新透明度
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
//控制动画
_controller = AnimationController(vsync: this, duration: const Duration(seconds: 1));
//设置补间
_animation = Tween<double>(
begin: 1,
end: 0.1,
).animate(_controller);
}
FadeTransition(
opacity: _animation,
child: Container(
color: Colors.green,
width: 120,
height: 120,
child: TextButton(
onPressed: () {
if (_controller.isCompleted) {
_controller.reverse();
}else {
_controller.forward();
}
},
child: const Text(
'fade动画',
style: TextStyle(color: Colors.white),
),
),
),
),
旋转
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
//控制动画
_controller = AnimationController(vsync: this, duration: const Duration(seconds: 1));
//设置补间
_animation = Tween<double>(
begin: 0,
end: 0.25,
).animate(_controller);
}
RotationTransition(
turns: _animation,
child: Container(
color: Colors.green,
width: 120,
height: 120,
child: TextButton(
onPressed: () {
if (_controller.isCompleted) {
_controller.reverse();
}else {
_controller.forward();
}
},
child: const Text(
'旋转动画',
style: TextStyle(color: Colors.white),
),
),
),
),
组合动画(显式动画中推荐)
看了上面的 Transition
操作,感觉也不是那么好用,功能单一,代码还多了,且有些变换操作还贼难用,下面有一个显式动画中比较常用的组合控件,可以避免使用上面的一些列 Transition
,且更加通用
AnimatedBuilder
:组合动画中比较常用的组件,可以避免使用 Transition
系列,其配合基础动画类,使用普通的组件 UI 即可实现动画效果,且不仅仅是组合动画,单个动画也可以哈
如下所示,我们定义多个 Animation
事件,然后应用到组件中即可形成组合动画了(单个就是用一个 Animation 即可)
class _CombinAnimatedWidgetState extends State<CombinAnimatedWidget> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _widthAnimation;
late Animation<double> _opacityAnimation;
late Animation<BorderRadius> _borderRadiusAnimation;
late Animation<double> _borderWidthAnimation;
@override
void initState() {
super.initState();
//控制动画
_controller = AnimationController(vsync: this, duration: const Duration(seconds: 1));
//设置补间
_widthAnimation = Tween<double>(
begin: 100,
end: 240,
).animate(_controller);
_opacityAnimation = Tween<double>(
begin: 1,
end: 0.6,
).animate(_controller);
_borderRadiusAnimation = Tween<BorderRadius>(
begin: const BorderRadius.all(Radius.circular(0)),
end: const BorderRadius.all(Radius.circular(120)),
).animate(_controller);
_borderWidthAnimation = Tween<double>(
begin: 1,
end: 20,
).animate(_controller);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("组合动画"),
),
body: Center(
child: GestureDetector(
onTap: () {
if (_controller.isCompleted) {
_controller.reverse();
}else {
_controller.forward();
}
},
//我们的动画组件,内部可以使用我们常用的控件
child: AnimatedBuilder(
animation: _controller,
builder: (BuildContext context, Widget? child) {
return Opacity(
opacity: _opacityAnimation.value,
child: Container(
width: _widthAnimation.value,
height: _widthAnimation.value,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: _borderRadiusAnimation.value,
border: Border.all(
width: _borderWidthAnimation.value,
color: Colors.cyanAccent
),
),
),
);
},
),
),
),
);
}
}
最后
基础动画,就是这么简单,使用时需要注意别被外部布局挤压等影响,以造成动画效果不正常的问题,一般使用 Stack 布局效果更好
转载自:https://juejin.cn/post/7169939264317161502