之前用 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;
  }
}



















![[PHP]严格类型](https://img-blog.csdnimg.cn/direct/aaf86b2bd14448d7953a6b4afb731358.png)

