3 changed files with 199 additions and 32 deletions
@ -0,0 +1,144 @@ |
|||||
|
import 'dart:math'; |
||||
|
|
||||
|
import 'package:flutter/material.dart'; |
||||
|
|
||||
|
class CircularFlowAnimation extends StatefulWidget { |
||||
|
const CircularFlowAnimation({super.key}); |
||||
|
|
||||
|
@override |
||||
|
State<CircularFlowAnimation> createState() => _CircularFlowAnimationState(); |
||||
|
} |
||||
|
|
||||
|
class _CircularFlowAnimationState extends State<CircularFlowAnimation> |
||||
|
with SingleTickerProviderStateMixin { |
||||
|
late AnimationController _controller; |
||||
|
|
||||
|
@override |
||||
|
void initState() { |
||||
|
super.initState(); |
||||
|
_controller = AnimationController( |
||||
|
vsync: this, |
||||
|
duration: const Duration(seconds: 20), |
||||
|
)..repeat(); |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
void dispose() { |
||||
|
_controller.dispose(); |
||||
|
super.dispose(); |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return CustomPaint( |
||||
|
painter: CircularFlowPainter(_controller), |
||||
|
size: Size.infinite, |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
class CircularFlowPainter extends CustomPainter { |
||||
|
final Animation<double> animation; |
||||
|
|
||||
|
CircularFlowPainter(this.animation) : super(repaint: animation); |
||||
|
|
||||
|
@override |
||||
|
void paint(Canvas canvas, Size size) { |
||||
|
final center = Offset(size.width / 2, size.height / 2); |
||||
|
const baseRadius = 150.0; |
||||
|
final time = animation.value * 2 * pi; |
||||
|
|
||||
|
// 绘制圆形路径 |
||||
|
_drawCircularPath(canvas, center, baseRadius); |
||||
|
|
||||
|
// 绘制三个围绕圆形运动的渐变云朵 |
||||
|
_drawOrbitingCloud( |
||||
|
canvas: canvas, |
||||
|
center: center, |
||||
|
time: time, |
||||
|
colors: [Colors.blue, Colors.purple], |
||||
|
orbitRadius: baseRadius, |
||||
|
speed: 0.5, |
||||
|
direction: 1, |
||||
|
); |
||||
|
|
||||
|
_drawOrbitingCloud( |
||||
|
canvas: canvas, |
||||
|
center: center, |
||||
|
time: time, |
||||
|
colors: [Colors.pink, Colors.orange], |
||||
|
orbitRadius: baseRadius * 0.8, |
||||
|
speed: 1.0, |
||||
|
direction: -1, |
||||
|
); |
||||
|
|
||||
|
_drawOrbitingCloud( |
||||
|
canvas: canvas, |
||||
|
center: center, |
||||
|
time: time, |
||||
|
colors: [Colors.green, Colors.yellow], |
||||
|
orbitRadius: baseRadius * 1.2, |
||||
|
speed: 0.3, |
||||
|
direction: 1, |
||||
|
); |
||||
|
|
||||
|
_drawOrbitingCloud( |
||||
|
canvas: canvas, |
||||
|
center: center, |
||||
|
time: time, |
||||
|
colors: [Colors.red, Colors.deepOrangeAccent], |
||||
|
orbitRadius: baseRadius * 0.5, |
||||
|
speed: 0.8, |
||||
|
direction: -1, |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
void _drawCircularPath(Canvas canvas, Offset center, double radius) { |
||||
|
final paint = Paint() |
||||
|
..color = Colors.red |
||||
|
..style = PaintingStyle.stroke |
||||
|
..strokeWidth = 2 |
||||
|
..maskFilter = MaskFilter.blur(BlurStyle.normal, 4); |
||||
|
|
||||
|
canvas.drawCircle(center, radius, paint); |
||||
|
} |
||||
|
|
||||
|
void _drawOrbitingCloud({ |
||||
|
required Canvas canvas, |
||||
|
required Offset center, |
||||
|
required double time, |
||||
|
required List<Color> colors, |
||||
|
required double orbitRadius, |
||||
|
required double speed, |
||||
|
required int direction, |
||||
|
}) { |
||||
|
final angle = time * speed * direction; |
||||
|
final position = Offset( |
||||
|
center.dx + orbitRadius * cos(angle), |
||||
|
center.dy + orbitRadius * sin(angle), |
||||
|
); |
||||
|
|
||||
|
final gradient = RadialGradient( |
||||
|
colors: colors, |
||||
|
stops: const [0.3, 1.0], |
||||
|
radius: 0.6, |
||||
|
focal: Alignment( |
||||
|
0.1 + cos(angle * 2) * 0.3, |
||||
|
0.1 + sin(angle * 2) * 0.3, |
||||
|
), |
||||
|
); |
||||
|
|
||||
|
final paint = Paint() |
||||
|
..shader = gradient.createShader(Rect.fromCircle( |
||||
|
center: position, |
||||
|
radius: 100 + 30 * sin(time * 3), |
||||
|
)) |
||||
|
..maskFilter = MaskFilter.blur(BlurStyle.normal, 40) |
||||
|
..blendMode = BlendMode.plus; |
||||
|
|
||||
|
canvas.drawCircle(position, 80 + 20 * cos(time * 2), paint); |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
bool shouldRepaint(covariant CustomPainter oldDelegate) => true; |
||||
|
} |
||||
Loading…
Reference in new issue