之前用 Flutter Canvas 画过一个三角三角形,html 的 Canvas 也画过一次类似的, 今天用 Flutter Canvas 试了下 感觉差不多:
html 版本
大致效果如下:
思路和 html 实现的类似:
也就是找出点的位置,使用二阶贝塞尔曲线实现:
代码如下:
import 'package:flutter/material.dart';
class PageCanvas extends StatefulWidget {
const PageCanvas({Key? key}) : super(key: key);
@override
State<PageCanvas> createState() => _PageCanvasState();
}
class _PageCanvasState extends State<PageCanvas> with TickerProviderStateMixin {
late Animation<double> animation;
late AnimationController controller;
@override
void initState() {
// TODO: implement initState
super.initState();
controller = AnimationController(
duration: const Duration(milliseconds: 2000), vsync: this);
animation = Tween<double>(begin: 0, end: 1).animate(controller);
controller.repeat();
}
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Scaffold(
appBar: AppBar(
title: const Text('Canvas'),
backgroundColor: Colors.blue,
),
body: Column(
children: [
AnimatedBuilder(
animation: controller,
builder: (context, widget) {
return CustomPaint(
size: Size(size.width, size.height / 3),
painter: MyPainter(animation.value),
);
}),
const SizedBox(
height: 60,
),
Center(
child: SizedBox(
// color: Colors.grey,
width: 200,
height: 200,
child: ClipOval(
child: Container(
color: Colors.grey.withOpacity(0.3),
child: AnimatedBuilder(
animation: controller,
builder: (context, widget) {
return CustomPaint(
size: Size(size.width, size.height / 3),
painter: MyPainter2(animation.value),
);
}),
),
),
),
)
],
),
);
}
@override
void dispose() {
controller.dispose();
// TODO: implement dispose
super.dispose();
}
}
class MyPainter extends CustomPainter {
final double value;
const MyPainter(this.value);
@override
void paint(Canvas canvas, Size size) {
// print(value);
Paint paint = Paint();
Path path = Path();
double positionX = -size.width * value;
double positionY = 100;
double positionRange = 10;
double positionX2 = -size.width * (1 - value);
double positionY2 = 110;
double positionRange2 = 20;
double positionX3 = -size.width * (1.3 - value);
double positionY3 = 120;
double positionRange3 = 30;
double step = size.width / 4;
//
path.moveTo(0 + positionX, positionY);
for (int i = 1; i < 13; i++) {
if (i % 2 == 1) {
path.quadraticBezierTo(step * (2 * i - 1) + positionX,
positionY - positionRange, step * (2 * i) + positionX, positionY);
} else {
path.quadraticBezierTo(step * (2 * i - 1) + positionX,
positionY + positionRange, step * (2 * i) + positionX, positionY);
}
}
path.lineTo(step * 10, 250);
path.lineTo(0, 250);
path.close();
paint.color = Colors.blue.withOpacity(0.2);
canvas.drawPath(path, paint);
canvas.save();
canvas.restore();
path = Path();
path.moveTo(0 + positionX2, positionY2);
for (int i = 1; i < 13; i++) {
if (i % 2 == 1) {
path.quadraticBezierTo(
step * (2 * i - 1) + positionX2,
positionY2 - positionRange2,
step * (2 * i) + positionX2,
positionY2);
} else {
path.quadraticBezierTo(
step * (2 * i - 1) + positionX2,
positionY2 + positionRange2,
step * (2 * i) + positionX2,
positionY2);
}
}
path.lineTo(step * 10, 250);
path.lineTo(0, 250);
path.close();
paint.color = Colors.blue.withOpacity(0.6);
canvas.drawPath(path, paint);
canvas.save();
canvas.restore();
path = Path();
path.moveTo(0 + positionX3, positionY3);
for (int i = 1; i < 13; i++) {
if (i % 2 == 1) {
path.quadraticBezierTo(
step * (2 * i - 1) + positionX3,
positionY3 - positionRange3,
step * (2 * i) + positionX3,
positionY3);
} else {
path.quadraticBezierTo(
step * (2 * i - 1) + positionX3,
positionY3 + positionRange3,
step * (2 * i) + positionX3,
positionY3);
}
}
path.lineTo(step * 10, 250);
path.lineTo(0, 250);
path.close();
paint.color = Colors.blue;
canvas.drawPath(path, paint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
// TODO: implement shouldRepaint
return oldDelegate != this;
//return true;
}
}
class MyPainter2 extends CustomPainter {
final double value;
const MyPainter2(this.value);
@override
void paint(Canvas canvas, Size size) {
// print(value);
Paint paint = Paint();
Path path = Path();
double positionX = -size.width * value;
double positionY = 50;
double positionRange = 10;
double positionX2 = -size.width * (1 - value);
double positionY2 = 60;
double positionRange2 = 20;
double positionX3 = -size.width * (1.3 - value);
double positionY3 = 70;
double positionRange3 = 30;
double step = size.width / 4;
//
path.moveTo(0 + positionX, positionY);
for (int i = 1; i < 13; i++) {
if (i % 2 == 0) {
path.quadraticBezierTo(step * (2 * i - 1) + positionX,
positionY - positionRange, step * (2 * i) + positionX, positionY);
} else {
path.quadraticBezierTo(step * (2 * i - 1) + positionX,
positionY + positionRange, step * (2 * i) + positionX, positionY);
}
}
path.lineTo(step * 10, 250);
path.lineTo(0, 250);
path.close();
paint.color = Colors.blue.withOpacity(0.2);
canvas.drawPath(path, paint);
canvas.save();
canvas.restore();
path = Path();
path.moveTo(0 + positionX2, positionY2);
for (int i = 1; i < 13; i++) {
if (i % 2 == 0) {
path.quadraticBezierTo(
step * (2 * i - 1) + positionX2,
positionY2 - positionRange2,
step * (2 * i) + positionX2,
positionY2);
} else {
path.quadraticBezierTo(
step * (2 * i - 1) + positionX2,
positionY2 + positionRange2,
step * (2 * i) + positionX2,
positionY2);
}
}
path.lineTo(step * 10, 250);
path.lineTo(0, 250);
path.close();
paint.color = Colors.blue.withOpacity(0.6);
canvas.drawPath(path, paint);
canvas.save();
canvas.restore();
path = Path();
path.moveTo(0 + positionX3, positionY3);
for (int i = 1; i < 13; i++) {
if (i % 2 == 0) {
path.quadraticBezierTo(
step * (2 * i - 1) + positionX3,
positionY3 - positionRange2,
step * (2 * i) + positionX3,
positionY3);
} else {
path.quadraticBezierTo(
step * (2 * i - 1) + positionX3,
positionY3 + positionRange2,
step * (2 * i) + positionX3,
positionY3);
}
}
path.lineTo(step * 10, 250);
path.lineTo(0, 250);
path.close();
paint.color = Colors.blue;
canvas.drawPath(path, paint);
canvas.save();
canvas.restore();
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
// TODO: implement shouldRepaint
return oldDelegate != this;
//return true;
}
}