Flutter添加动画

Flutter有许多不同的方式来实现各种动画效果。

1.显式动画(Explicit Animations)

显式动画通过AnimationController来控制动画状态,通常用于处理需要手动控制的动画效果。



_controller = AnimationController(
vsync: this, // 必须传入一个TickerProvider,通常为当前State对象
duration: const Duration(seconds: 2), // 设置动画持续时间
);

_animation = Tween(begin: 0.0, end: 1.0).animate(_controller);

// // 添加动画状态监听,可以在动画状态改变时执行自定义逻辑
_controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
_controller.reverse(); // 当动画完成时,反向播放动画
} else if (status == AnimationStatus.dismissed) {
_controller.forward(); // 当动画回到初始状态时,正向播放动画
}
});

void showExplicitAnimations() {
showDialog(
context: context,
builder: (context) {
return Center(
child: AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Transform.scale(
scale: _animation.value,
child: AlertDialog(
title: const Text('Animated Dialog'),
content: const Text('This is an animated dialog.'),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Close'),
),
],
),
);
},
),
);
},
);


_controller.reset();
_controller.forward();

}

2. 隐式动画(Implicit Animations)

隐式动画通过Flutter内置的小部件处理动画效果,比如在小部件属性变化时自动执行动画。

//控制效果切换
bool _isVisible = false;

void showImplicitAnimations() {
setState(() {
_isVisible = !_isVisible;
});
}


AnimatedContainer(
duration: const Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
width: _isVisible ? 300.0 : 200.0,
height: _isVisible ? 50.0 : 200.0,
color: _isVisible ? Colors.blue : Colors.red,
child: const Center(
child: Text(
'切换颜色和大小',
style: TextStyle(color: Colors.white),
),
),
),




3.物理动画(Physics-based Animation)

可以使用AnimatedPhysicalModel或ScrollPhysics等来创建物理效果动画。

//控制效果切换
bool _isLarge = false;

void showPhysicsBasedAnimation() {
setState(() {
_isLarge = !_isLarge;
});
}

AnimatedPhysicalModel(
duration: const Duration(milliseconds: 500),
shape: BoxShape.rectangle,
elevation: _isLarge ? 20 : 0,
color: _isLarge ? Colors.blue : Colors.purple,
shadowColor: Colors.black,
borderRadius:
_isLarge ? BorderRadius.circular(20) : BorderRadius.circular(0),
child: const SizedBox(
width: 200,
height: 80,
child: Center(
child: Text('切换大小',
style: TextStyle(color: Colors.white),
),
),
),
),

4. 自定义动画(Custom Animations)

通过使用CustomPainter构建自定义绘制动画,您可以实现几乎任何动画效果。下面实现一个放大的圆

//在初始化状态时初始化
_customController = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)..repeat(reverse: true);

_customAnimation =
Tween<double>(begin: 0, end: 100).animate(_customController)
..addListener(() {
setState(() {});
});

// 子控件嵌入页面
CustomPaint(
painter: MyCustomPainter(_customAnimation.value),
child: const SizedBox(
width: 200,
height: 200,
),
),

// 自定义圆
class MyCustomPainter extends CustomPainter {
final double radius;
MyCustomPainter(this.radius);

@override
void paint(Canvas canvas, Size size) {
debugPrint('size:$size, radius:$radius');
final paint = Paint();
paint.color = Colors.green;
paint.style = PaintingStyle.fill;

canvas.drawCircle(Offset(size.width / 2, size.height / 2), radius, paint);
}

@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}

5.完整示例代码


import 'package:flutter/material.dart';

class AnimationsWidget extends StatefulWidget {
const AnimationsWidget({super.key});

@override
AnimationsWidgetState createState() => AnimationsWidgetState();
}

class AnimationsWidgetState extends State<AnimationsWidget>
with TickerProviderStateMixin {
late AnimationController _controller;
late AnimationController _customController;
late Animation<double> _animation;
late Animation<double> _customAnimation;
bool _isVisible = false;
bool _isLarge = false;

@override
void initState() {
super.initState();

_controller = AnimationController(
vsync: this, // 必须传入一个TickerProvider,通常为当前State对象
duration: const Duration(seconds: 2), // 设置动画持续时间
);

_animation = Tween(begin: 0.0, end: 1.0).animate(_controller);

// // 添加动画状态监听,可以在动画状态改变时执行自定义逻辑
_controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
_controller.reverse(); // 当动画完成时,反向播放动画
} else if (status == AnimationStatus.dismissed) {
_controller.forward(); // 当动画回到初始状态时,正向播放动画
}
});

_customController = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)..repeat(reverse: true);

_customAnimation =
Tween<double>(begin: 0, end: 100).animate(_customController)
..addListener(() {
setState(() {});
});
}

@override
void dispose() {
_controller.dispose();
_customController.dispose(); // 在组件销毁时释放AnimationController
super.dispose();
}

@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () {
showExplicitAnimations();
},
child: const Text('显式动画')),
const SizedBox(
height: 20,
),

// AnimatedOpacity(
// opacity: _visible ? 1.0 : 0.0,
// duration: const Duration(seconds: 1),
// child: Container(
// width: 200,
// height: _visible? 100 : 0,
// color: Colors.blue,
// ),
// ),
AnimatedContainer(
duration: const Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
width: _isVisible ? 300.0 : 200.0,
height: _isVisible ? 50.0 : 200.0,
color: _isVisible ? Colors.blue : Colors.red,
child: const Center(
child: Text(
'切换颜色和大小',
style: TextStyle(color: Colors.white),
),
),
),

ElevatedButton(
onPressed: () {
showImplicitAnimations();
},
child: const Text('隐式动画')),
const SizedBox(
height: 20,
),

AnimatedPhysicalModel(
duration: const Duration(milliseconds: 500),
shape: BoxShape.rectangle,
elevation: _isLarge ? 20 : 0,
color: _isLarge ? Colors.blue : Colors.purple,
shadowColor: Colors.black,
borderRadius:
_isLarge ? BorderRadius.circular(20) : BorderRadius.circular(0),
child: const SizedBox(
width: 200,
height: 80,
child: Center(
child: Text(
'切换大小',
style: TextStyle(color: Colors.white),
),
),
),
),
ElevatedButton(
onPressed: () {
showPhysicsBasedAnimation();
},
child: const Text(' 物理动画')),
const SizedBox(
height: 20,
),

CustomPaint(
painter: MyCustomPainter(_customAnimation.value),
child: const SizedBox(
width: 200,
height: 200,
),
),
ElevatedButton(
onPressed: () {
showCustomAnimations();
},
child: const Text('自定义动画')),
],
));
}

void showExplicitAnimations() {
showDialog(
context: context,
builder: (context) {
return Center(
child: AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Transform.scale(
scale: _animation.value,
child: AlertDialog(
title: const Text('Animated Dialog'),
content: const Text('This is an animated dialog.'),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Close'),
),
],
),
);
},
),
);
},
);

_controller.reset();
_controller.forward();
}

void showImplicitAnimations() {
setState(() {
_isVisible = !_isVisible;
});
}

void showPhysicsBasedAnimation() {
setState(() {
_isLarge = !_isLarge;
});
}

void showCustomAnimations() {
_customController.reset();
_customController.forward();
}
}

class MyCustomPainter extends CustomPainter {
final double radius;

MyCustomPainter(this.radius);

@override
void paint(Canvas canvas, Size size) {
debugPrint('size:$size, radius:$radius');
final paint = Paint();
paint.color = Colors.green;
paint.style = PaintingStyle.fill;

canvas.drawCircle(Offset(size.width / 2, size.height / 2), radius, paint);
}

@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}

6.效果

Flutter添加动画

Flutter添加动画

Flutter添加动画


原文始发于微信公众号(ksnowlv):Flutter添加动画

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/261336.html

(0)
newbe的头像newbebm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!