177 lines
3.8 KiB
Dart
177 lines
3.8 KiB
Dart
import 'dart:math';
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
/// 音频波形动画组件
|
|
/// 用于显示音频播放时的动态波形效果
|
|
class AudioWaveView extends StatefulWidget {
|
|
/// 波形高度
|
|
final double height;
|
|
|
|
/// 波形颜色
|
|
final Color color;
|
|
|
|
/// 动画持续时间
|
|
final Duration duration;
|
|
|
|
/// 动画曲线
|
|
final Curve curve;
|
|
|
|
/// 波形条之间的间距
|
|
final double margin;
|
|
|
|
/// 波形条的宽度
|
|
final double width;
|
|
|
|
/// 波形条的数量
|
|
final int barCount;
|
|
|
|
const AudioWaveView({
|
|
super.key,
|
|
this.height = 12,
|
|
this.margin = 3,
|
|
this.width = 1.5,
|
|
this.color = const Color(0xffF68804),
|
|
this.duration = const Duration(seconds: 5),
|
|
this.curve = Curves.easeInOut,
|
|
this.barCount = 3,
|
|
});
|
|
|
|
@override
|
|
State<AudioWaveView> createState() => _AudioWaveViewState();
|
|
}
|
|
|
|
class _AudioWaveViewState extends State<AudioWaveView>
|
|
with SingleTickerProviderStateMixin {
|
|
late AnimationController _controller;
|
|
late List<Animation<double>> _animations;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_initializeAnimations();
|
|
}
|
|
|
|
/// 初始化动画
|
|
void _initializeAnimations() {
|
|
_controller = AnimationController(
|
|
vsync: this,
|
|
duration: widget.duration,
|
|
);
|
|
|
|
_animations = _createWaveAnimations();
|
|
_controller.repeat();
|
|
}
|
|
|
|
/// 创建波形动画列表
|
|
List<Animation<double>> _createWaveAnimations() {
|
|
const int sequenceCount = 15;
|
|
final List<Animation<double>> animations = [];
|
|
|
|
for (int i = 0; i < widget.barCount; i++) {
|
|
final source = _generateRandomSequence(sequenceCount);
|
|
|
|
final tweenSequence = TweenSequence<double>(
|
|
List.generate(sequenceCount, (index) {
|
|
return TweenSequenceItem<double>(
|
|
tween: Tween<double>(
|
|
begin: source[index],
|
|
end: source[index + 1],
|
|
),
|
|
weight: 100.0 / sequenceCount,
|
|
);
|
|
}),
|
|
);
|
|
|
|
animations.add(
|
|
tweenSequence.animate(
|
|
CurvedAnimation(
|
|
parent: _controller,
|
|
curve: widget.curve,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
return animations;
|
|
}
|
|
|
|
/// 生成随机序列
|
|
List<double> _generateRandomSequence(int count) {
|
|
final random = Random();
|
|
final source = List.generate(count, (_) => random.nextDouble());
|
|
source.add(source.first); // 确保循环
|
|
return source;
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_controller.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return AnimatedBuilder(
|
|
animation: _controller,
|
|
builder: (context, child) {
|
|
return Row(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: _buildWaveBars(),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
/// 构建波形条列表
|
|
List<Widget> _buildWaveBars() {
|
|
final List<Widget> bars = [];
|
|
|
|
for (int i = 0; i < widget.barCount; i++) {
|
|
if (i > 0) {
|
|
bars.add(SizedBox(width: widget.margin));
|
|
}
|
|
|
|
bars.add(
|
|
WaveBar(
|
|
color: widget.color,
|
|
width: widget.width,
|
|
height: _animations[i].value * widget.height,
|
|
),
|
|
);
|
|
}
|
|
|
|
return bars;
|
|
}
|
|
}
|
|
|
|
/// 单个波形条组件
|
|
class WaveBar extends StatelessWidget {
|
|
final double width;
|
|
final double height;
|
|
final Color color;
|
|
|
|
const WaveBar({
|
|
super.key,
|
|
required this.width,
|
|
required this.height,
|
|
required this.color,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return SizedBox(
|
|
width: width,
|
|
height: height,
|
|
child: DecoratedBox(
|
|
decoration: BoxDecoration(
|
|
color: color,
|
|
borderRadius: BorderRadius.circular(width / 2),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|