Files
ai_chat_assistant/lib/widgets/voice_animation.dart
Chen Li 130755f9e1 0812
2025-08-12 13:36:42 +08:00

113 lines
2.9 KiB
Dart

import 'dart:math';
import 'package:flutter/material.dart';
class VoiceWaveAnimation extends StatefulWidget {
const VoiceWaveAnimation({super.key});
@override
State<VoiceWaveAnimation> createState() => _VoiceWaveAnimationState();
}
class _VoiceWaveAnimationState extends State<VoiceWaveAnimation> with TickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
super.initState();
// 创建一个持续动画控制器
_controller = AnimationController(
duration: const Duration(milliseconds: 1500),
vsync: this,
)..repeat();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return SizedBox(
width: 160,
height: 30,
child: CustomPaint(
painter: SineWavePainter(
animation: _controller,
count: 2, // 波浪数量
color: Colors.white,
amplitudeFactor: 0.5, // 波幅因子
),
),
);
},
);
}
}
class SineWavePainter extends CustomPainter {
final Animation<double> animation;
final int count; // 波浪数量
final Color color;
final double amplitudeFactor; // 波幅因子
SineWavePainter({
required this.animation,
this.count = 2,
required this.color,
this.amplitudeFactor = 1.0,
});
@override
void paint(Canvas canvas, Size size) {
final Paint paint = Paint()
..color = color.withValues(alpha: 0.7)
..style = PaintingStyle.stroke
..strokeWidth = 2.0;
final Paint paint2 = Paint()
..color = color.withValues(alpha: 0.3)
..style = PaintingStyle.stroke
..strokeWidth = 2.0;
final double width = size.width;
final double height = size.height;
final double centerY = height / 2;
// 绘制第一个波浪
final path = Path();
final path2 = Path();
// 创建两条不同相位的波形,一条主要一条次要
path.moveTo(0, centerY);
path2.moveTo(0, centerY);
for (int i = 0; i < width; i++) {
// 主波形
final double x = i.toDouble();
final double normalizedX = (x / width) * count * 2 * pi;
final double offset = 2 * pi * animation.value;
// 使用随机振幅变化模拟声音波动
final double randomAmplitude = (sin(normalizedX + offset) + 1) / 2 * amplitudeFactor;
path.lineTo(x, centerY - randomAmplitude * 10);
// 次波形,相位滞后
final double randomAmplitude2 = (sin(normalizedX + offset + pi / 6) + 1) / 2 * amplitudeFactor;
path2.lineTo(x, centerY - randomAmplitude2 * 5);
}
canvas.drawPath(path, paint);
canvas.drawPath(path2, paint2);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}