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
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;
|
|
}
|