You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

89 lines
2.4 KiB

import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_shaders/flutter_shaders.dart';
class VoiceMicFlow extends StatefulWidget {
const VoiceMicFlow({super.key, this.size = 280, this.amp = 0.0});
final double size;
final double amp; // 音量振幅 0.0-1.0
@override
State<VoiceMicFlow> createState() => _VoiceMicFlowState();
}
class _VoiceMicFlowState extends State<VoiceMicFlow>
with SingleTickerProviderStateMixin {
late final AnimationController _ctl;
@override
void initState() {
super.initState();
_ctl = AnimationController(
duration: const Duration(seconds: 100), // 100秒的长周期
vsync: this,
)..repeat();
}
@override
void dispose() {
_ctl.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return ClipOval(
child: ShaderBuilder(
assetKey: 'shaders/mic_flow.frag',
(context, shader, child) {
return AnimatedBuilder(
animation: _ctl,
builder: (_, __) {
// 将0.0-1.0的动画值映射到更大的时间范围
final time = _ctl.value * 100.0;
shader
..setFloat(0, widget.size) // u_resolution.x
..setFloat(1, widget.size) // u_resolution.y
..setFloat(2, time) // u_time
..setFloat(3, widget.amp); // u_amp (音量振幅)
return CustomPaint(
size: Size.square(widget.size),
painter: _ShaderPainter(shader),
);
},
);
},
// 着色器编译时的占位符
child: Container(
width: widget.size,
height: widget.size,
decoration: const BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Color(0xFF1565C0), // 深蓝
Color(0xFFE3F2FD), // 浅蓝
],
),
),
),
),
);
}
}
class _ShaderPainter extends CustomPainter {
_ShaderPainter(this.shader);
final FragmentShader shader;
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()..shader = shader;
canvas.drawRect(Offset.zero & size, paint);
}
@override
bool shouldRepaint(covariant _ShaderPainter oldDelegate) => true;
}