如何解决如何在 Flutter 中创建 Wave 小部件
我们知道波浪动画效果,所以我想在我的 Flutter 应用程序中使用这个效果
如何创建一个小部件,用于在颤动中显示具有自定义颜色和模糊效果的波浪。
我想要这样的东西
解决方法
为了达到这个目的,首先创建 WaveWidget
类
import 'dart:math';
import 'package:flutter/widgets.dart';
import 'package:prokit_flutter/main/utils/wave/config.dart';
class WaveWidget extends StatefulWidget {
final Config config;
final Size size;
final double waveAmplitude;
final double wavePhase;
final double waveFrequency;
final double heightPercentange;
final int duration;
final Color backgroundColor;
WaveWidget({
@required this.config,this.duration = 6000,@required this.size,this.waveAmplitude = 20.0,this.waveFrequency = 1.6,this.wavePhase = 10.0,this.backgroundColor,this.heightPercentange = 0.2,});
@override
State<StatefulWidget> createState() => _WaveWidgetState();
}
class _WaveWidgetState extends State<WaveWidget> with TickerProviderStateMixin {
List<AnimationController> _waveControllers;
List<Animation<double>> _wavePhaseValues;
List<double> _waveAmplitudes = [];
Map<Animation<double>,AnimationController> valueList;
_initAnimations() {
if (widget.config.colorMode == ColorMode.custom) {
_waveControllers =
(widget.config as CustomConfig).durations.map((duration) {
_waveAmplitudes.add(widget.waveAmplitude + 10);
return AnimationController(
vsync: this,duration: Duration(milliseconds: duration));
}).toList();
_wavePhaseValues = _waveControllers.map((controller) {
CurvedAnimation _curve =
CurvedAnimation(parent: controller,curve: Curves.easeInOut);
Animation<double> value = Tween(
begin: widget.wavePhase,end: 360 + widget.wavePhase,).animate(
_curve,);
value.addStatusListener((status) {
switch (status) {
case AnimationStatus.completed:
controller.reverse();
break;
case AnimationStatus.dismissed:
controller.forward();
break;
default:
break;
}
});
controller.forward();
return value;
}).toList();
}
}
_buildPaints() {
List<Widget> paints = [];
if (widget.config.colorMode == ColorMode.custom) {
List<Color> _colors = (widget.config as CustomConfig).colors;
List<List<Color>> _gradients = (widget.config as CustomConfig).gradients;
Alignment begin = (widget.config as CustomConfig).gradientBegin;
Alignment end = (widget.config as CustomConfig).gradientEnd;
for (int i = 0; i < _wavePhaseValues.length; i++) {
paints.add(
Container(
child: CustomPaint(
painter: _CustomWavePainter(
color: _colors == null ? null : _colors[i],gradient: _gradients == null ? null : _gradients[i],gradientBegin: begin,gradientEnd: end,heightPercentange:
(widget.config as CustomConfig).heightPercentages[i],repaint: _waveControllers[i],waveFrequency: widget.waveFrequency,wavePhaseValue: _wavePhaseValues[i],waveAmplitude: _waveAmplitudes[i],blur: (widget.config as CustomConfig).blur,),size: widget.size,);
}
}
return paints;
}
_disposeAnimations() {
_waveControllers.forEach((controller) {
controller.dispose();
});
}
@override
void initState() {
super.initState();
_initAnimations();
}
@override
void dispose() {
_disposeAnimations();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
color: widget.backgroundColor,child: Stack(
children: _buildPaints(),);
}
}
/// Meta data of layer
class Layer {
final Color color;
final List<Color> gradient;
final MaskFilter blur;
final Path path;
final double amplitude;
final double phase;
Layer({
this.color,this.gradient,this.blur,this.path,this.amplitude,this.phase,});
}
class _CustomWavePainter extends CustomPainter {
final ColorMode colorMode;
final Color color;
final List<Color> gradient;
final Alignment gradientBegin;
final Alignment gradientEnd;
final MaskFilter blur;
double waveAmplitude;
Animation<double> wavePhaseValue;
double waveFrequency;
double heightPercentange;
double _tempA = 0.0;
double _tempB = 0.0;
double viewWidth = 0.0;
Paint _paint = Paint();
_CustomWavePainter(
{this.colorMode,this.color,this.gradientBegin,this.gradientEnd,this.heightPercentange,this.waveFrequency,this.wavePhaseValue,this.waveAmplitude,Listenable repaint})
: super(repaint: repaint);
_setPaths(double viewCenterY,Size size,Canvas canvas) {
Layer _layer = Layer(
path: Path(),color: color,gradient: gradient,blur: blur,amplitude: (-1.6 + 0.8) * waveAmplitude,phase: wavePhaseValue.value * 2 + 30,);
_layer.path.reset();
_layer.path.moveTo(
0.0,viewCenterY +
_layer.amplitude * _getSinY(_layer.phase,waveFrequency,-1));
for (int i = 1; i < size.width + 1; i++) {
_layer.path.lineTo(
i.toDouble(),viewCenterY +
_layer.amplitude * _getSinY(_layer.phase,i));
}
_layer.path.lineTo(size.width,size.height);
_layer.path.lineTo(0.0,size.height);
_layer.path.close();
if (_layer.color != null) {
_paint.color = _layer.color;
}
if (_layer.gradient != null) {
var rect = Offset.zero &
Size(size.width,size.height - viewCenterY * heightPercentange);
_paint.shader = LinearGradient(
begin: gradientBegin == null
? Alignment.bottomCenter
: gradientBegin,end: gradientEnd == null ? Alignment.topCenter : gradientEnd,colors: _layer.gradient)
.createShader(rect);
}
if (_layer.blur != null) {
_paint.maskFilter = _layer.blur;
}
_paint.style = PaintingStyle.fill;
canvas.drawPath(_layer.path,_paint);
}
@override
void paint(Canvas canvas,Size size) {
double viewCenterY = size.height * (heightPercentange + 0.1);
viewWidth = size.width;
_setPaths(viewCenterY,size,canvas);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return false;
}
double _getSinY(
double startradius,double waveFrequency,int currentposition) {
if (_tempA == 0) {
_tempA = pi / viewWidth;
}
if (_tempB == 0) {
_tempB = 2 * pi / 360.0;
}
return (sin(
_tempA * waveFrequency * (currentposition + 1) + startradius * _tempB));
}
}
制作 Config
类进行配置
import 'dart:ui';
import 'package:flutter/widgets.dart';
enum ColorMode {
/// Waves with *single* **color** but different **alpha** and **amplitude**.
single,/// Waves using *random* **color**,**alpha** and **amplitude**.
random,/// Waves' colors must be set,and [colors]'s length must equal with [layers]
custom,}
abstract class Config {
final ColorMode colorMode;
Config({this.colorMode});
void throwNullError(String colorModeStr,String configStr) {
throw FlutterError(
'When using `ColorMode.$colorModeStr`,`$configStr` must be set.');
}
}
class CustomConfig extends Config {
final List<Color> colors;
final List<List<Color>> gradients;
final Alignment gradientBegin;
final Alignment gradientEnd;
final List<int> durations;
final List<double> heightPercentages;
final MaskFilter blur;
CustomConfig({
this.colors,this.gradients,@required this.durations,@required this.heightPercentages,}) : assert(() {
if (colors == null && gradients == null) {
throw 'colors` or `gradients';
}
return true;
}()),assert(() {
if (gradients == null &&
(gradientBegin != null || gradientEnd != null)) {
throw FlutterError(
'You set a gradient direction but forgot setting `gradients`.');
}
return true;
}()),assert(() {
if (durations == null) {
throw 'durations';
}
return true;
}()),assert(() {
if (heightPercentages == null) {
throw 'heightPercentages';
}
return true;
}()),assert(() {
if (colors != null) {
if (colors.length != durations.length ||
colors.length != heightPercentages.length) {
throw FlutterError(
'Length of `colors`,`durations` and `heightPercentages` must be equal.');
}
}
return true;
}()),assert(colors == null || gradients == null,'Cannot provide both colors and gradients.'),super(colorMode: ColorMode.custom);
}
/// todo
class RandomConfig extends Config {
RandomConfig() : super(colorMode: ColorMode.random);
}
/// todo
class SingleConfig extends Config {
SingleConfig() : super(colorMode: ColorMode.single);
}
在屏幕中导入这两个类并像这样使用它们
class WaveScreen extends StatefulWidget {
static String tag = '/WaveScreen';
@override
WaveScreenState createState() => WaveScreenState();
}
class WaveScreenState extends State<WaveScreen> {
@override
Widget build(BuildContext context) {
changeStatusColor(appColorPrimary);
return Scaffold(
appBar: appBar(context,"Wave Widget"),body: WaveWidget(
config: CustomConfig(
gradients: [
[Color(0xFF676B76),Color(0xEE676B76)],[Color(0xFFECB099),Color(0xEEECB099)],[Color(0xFFdea34b),Color(0xEEdea34b)],[Color(0xFFA3CEB6),Color(0xEEA3CEB6)],],durations: [35000,19440,10800,6000],heightPercentages: [0.20,0.23,0.25,0.30],blur: MaskFilter.blur(BlurStyle.solid,10),gradientBegin: Alignment.bottomLeft,gradientEnd: Alignment.topRight,waveAmplitude: 0,backgroundColor: Colors.white,size: Size(double.infinity,double.infinity),);
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。