193 lines
5.5 KiB
Dart
193 lines
5.5 KiB
Dart
|
|
import 'package:flutter/material.dart';
|
|
import '../components/coordinate_pro.dart';
|
|
|
|
/// create by 张风捷特烈 on 2020/5/1
|
|
/// contact me by email 1981462002@qq.com
|
|
/// 说明:
|
|
|
|
class Paper extends StatelessWidget {
|
|
const Paper({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Center(child: Wrap(
|
|
spacing: 30,
|
|
runSpacing: 30,
|
|
children: List.generate(12, (v) => 0.1 * v+0.1)
|
|
.map((e) => TolyWaveLoading(
|
|
isOval: (e*10).toInt().isEven, // 是否椭圆裁切
|
|
progress: 0.5, // 进度
|
|
waveHeight: 3, //波浪高
|
|
color: [Colors.blue,Colors.red,Colors.green][(e*10).toInt()%3], //颜色
|
|
)).toList(),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class TolyWaveLoading extends StatefulWidget {
|
|
// 波高
|
|
final double waveHeight;
|
|
|
|
// 进度
|
|
final double progress;
|
|
|
|
// 颜色
|
|
final Color color;
|
|
|
|
// 尺寸
|
|
final Size size;
|
|
|
|
// 底波透明度
|
|
final int secondAlpha;
|
|
|
|
// 边线宽
|
|
final double strokeWidth;
|
|
|
|
// 圆角半径
|
|
final double borderRadius;
|
|
|
|
// 是否是椭圆
|
|
final bool isOval;
|
|
final Duration duration;
|
|
|
|
final Curve curve;
|
|
|
|
const TolyWaveLoading(
|
|
{Key? key,
|
|
this.waveHeight = 5,
|
|
this.progress = 0.5,
|
|
this.duration = const Duration(seconds: 1),
|
|
this.size = const Size(100, 100),
|
|
this.color = Colors.green,
|
|
this.secondAlpha = 88,
|
|
this.strokeWidth = 3,
|
|
this.curve = Curves.linear,
|
|
this.borderRadius = 20,
|
|
this.isOval = false})
|
|
: super(key: key);
|
|
|
|
@override
|
|
_TolyWaveLoadingState createState() => _TolyWaveLoadingState();
|
|
}
|
|
|
|
class _TolyWaveLoadingState extends State<TolyWaveLoading>
|
|
with SingleTickerProviderStateMixin {
|
|
late AnimationController _controller;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_controller = AnimationController(
|
|
duration: widget.duration,
|
|
vsync: this,
|
|
)..repeat();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_controller.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return CustomPaint(
|
|
size: widget.size,
|
|
painter: PaperPainter(
|
|
waveHeight: widget.waveHeight,
|
|
secondAlpha: widget.secondAlpha,
|
|
color: widget.color,
|
|
borderRadius: widget.borderRadius,
|
|
isOval: widget.isOval,
|
|
progress: widget.progress,
|
|
strokeWidth: widget.strokeWidth,
|
|
repaint: CurveTween(curve: widget.curve).animate(_controller)),
|
|
);
|
|
}
|
|
}
|
|
|
|
class PaperPainter extends CustomPainter {
|
|
final Animation<double> repaint;
|
|
|
|
PaperPainter({
|
|
required this.repaint,
|
|
required this.waveHeight,
|
|
required this.color,
|
|
required this.progress,
|
|
required this.secondAlpha,
|
|
required this.borderRadius,
|
|
required this.isOval,
|
|
required this.strokeWidth,
|
|
}) : super(repaint: repaint);
|
|
|
|
final double waveHeight;
|
|
final double progress;
|
|
final Color color;
|
|
final double strokeWidth;
|
|
final int secondAlpha;
|
|
final double borderRadius;
|
|
final bool isOval;
|
|
Path path = Path();
|
|
Paint _mainPaint = Paint();
|
|
Path _mainPath = Path();
|
|
double waveWidth = 0;
|
|
double wrapHeight = 0;
|
|
|
|
@override
|
|
void paint(Canvas canvas, Size size) {
|
|
// 由于 使用 repaint 触发更新 path 和 _mainPath 不会重新创建
|
|
// 而导致刷新时不断为 path 和 _mainPath 添加路径,导致路径非常庞大,越来越卡,而掉帧
|
|
// 处理方案一: 绘制前 重置 path 或者
|
|
// 处理方案二: 不将 path 设为成员变量,每次绘制都新建 Path 对象,这样会造成大量 Path 对象创建,测试发现两种方案结果差不多。
|
|
path.reset();
|
|
_mainPath.reset();
|
|
|
|
waveWidth = size.width / 2;
|
|
wrapHeight = size.height;
|
|
|
|
_mainPaint..strokeWidth = strokeWidth..style = PaintingStyle.stroke..color = color;
|
|
|
|
if (!isOval) {
|
|
path.addRRect(RRect.fromRectXY(Offset(0, 0) & size, borderRadius, borderRadius));
|
|
canvas.clipPath(path);
|
|
canvas.drawPath(path,_mainPaint);
|
|
}
|
|
if (isOval) {
|
|
path.addOval(Offset(0, 0) & size);
|
|
canvas.clipPath(path);
|
|
canvas.drawPath(path, _mainPaint);
|
|
}
|
|
|
|
canvas.translate(-4 * waveWidth + 2 * waveWidth * repaint.value, wrapHeight + waveHeight);
|
|
drawWave(canvas);
|
|
canvas.drawPath(_mainPath, _mainPaint..style = PaintingStyle.fill..color = color);
|
|
|
|
canvas.translate(2 * waveWidth * repaint.value, 0);
|
|
drawWave(canvas);
|
|
canvas.drawPath(_mainPath, _mainPaint..color = color.withAlpha(88));
|
|
}
|
|
|
|
void drawWave(Canvas canvas) {
|
|
_mainPath.moveTo(0, 0);
|
|
_mainPath.relativeLineTo(0, -wrapHeight * progress);
|
|
_mainPath.relativeQuadraticBezierTo(waveWidth / 2, -waveHeight * 2, waveWidth, 0);
|
|
_mainPath.relativeQuadraticBezierTo(waveWidth / 2, waveHeight * 2, waveWidth, 0);
|
|
_mainPath.relativeQuadraticBezierTo(waveWidth / 2, -waveHeight * 2, waveWidth, 0);
|
|
_mainPath.relativeQuadraticBezierTo(waveWidth / 2, waveHeight * 2, waveWidth, 0);
|
|
_mainPath.relativeQuadraticBezierTo(waveWidth / 2, -waveHeight * 2, waveWidth, 0);
|
|
_mainPath.relativeQuadraticBezierTo(waveWidth / 2, waveHeight * 2, waveWidth, 0);
|
|
_mainPath.relativeLineTo(0, wrapHeight);
|
|
_mainPath.relativeLineTo(-waveWidth * 3 * 2.0, 0);
|
|
}
|
|
|
|
@override
|
|
bool shouldRepaint(PaperPainter oldDelegate) =>
|
|
oldDelegate.repaint != repaint|| oldDelegate.waveHeight != waveHeight||
|
|
oldDelegate.progress != progress|| oldDelegate.color != color||
|
|
oldDelegate.strokeWidth != strokeWidth|| oldDelegate.isOval != isOval||
|
|
oldDelegate.secondAlpha != secondAlpha|| oldDelegate.borderRadius != borderRadius;
|
|
}
|
|
|