Flutter PainterPath


简介

在 canvas 上绘制的图案,canvas + paint 的应用。

基本用法

  • canvas 的 painter 的自定义绘制线的方法;

绘制简单直线

绘制折线

二阶贝塞尔曲线

三阶贝塞尔曲线

实例演示

import 'dart:ui';
import 'package:flutter/material.dart';
CustomPaint graph;

class CustomViewPage extends StatefulWidget {

  final String type;
  CustomViewPage({this.type='simpleline'}) : super();

  @override
  State<StatefulWidget> createState() => CustomViewPageState();
}

class CustomViewPageState extends State<CustomViewPage>
    with SingleTickerProviderStateMixin {

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    graph = CustomPaint(
        painter: DrawPainter(type:widget.type)
    );
    return Container(
        width: MediaQuery.of(context).size.width,
        height: MediaQuery.of(context).size.width * 0.6,
        margin: EdgeInsets.all(50.0),
        //padding: EdgeInsets.all(10.0),
        child: graph
        //child:Center(child: graph)
    );
  }


  @override
  void reassemble() {
    super.reassemble();
  }

  @override
  void dispose() {
    super.dispose();
  }
}

///新建类继承于CustomPainter并且实现CustomPainter里面的paint()和shouldRepaint方法
class DrawPainter extends CustomPainter {
  Paint painter;
  final type;

  DrawPainter ({this.type}){
    //    Paint painter = Paint()
    //    ..color = Colors.blueAccent //画笔颜色
    //    ..strokeCap = StrokeCap.round //画笔笔触类型
    //    ..isAntiAlias = true //是否启动抗锯齿
    //    ..blendMode = BlendMode.exclusion //颜色混合模式
    //    ..style = PaintingStyle.fill //绘画风格,默认为填充
    //    ..colorFilter = ColorFilter.mode(Colors.blueAccent,BlendMode.exclusion) //颜色渲染模式,一般是矩阵效果来改变的,但是flutter中只能使用颜色混合模式
    //    ..maskFilter = MaskFilter.blur(BlurStyle.inner, 3.0) //模糊遮罩效果,flutter中只有这个
    //    ..filterQuality = FilterQuality.high //颜色渲染模式的质量
    //    ..strokeWidth = 15.0 ;//画笔的宽度

    painter = new Paint()
      ..color = Colors.blueAccent
      ..strokeCap = StrokeCap.round
      ..isAntiAlias = true
      ..strokeWidth = 5.0
      ..style = PaintingStyle.stroke;
  }
  ///Flutter中负责View绘制的地方,使用传递来的canvas和size即可完成对目标View的绘制

  @override
  void paint(Canvas canvas, Size size) {
    //canvas.drawColor(Colors.red, BlendMode.colorDodge);
    Path path = new Path();
    drawThisPath(canvas, size, path);
    path.close();
    canvas.drawPath(path, painter);
  }

  void drawThisPath(Canvas canvas, Size size, Path path,) {
    switch(type) {
      case 'simpleline':
      //新建了一个path,然后将路径起始点移动到坐标(100,100)的位置
        Path path = new Path()..moveTo(0.0, 0.0);
        path.lineTo(200.0, 200.0);
        canvas.drawPath(path, painter);
        break;
      case 'polyline':
        Path path = new Path()..moveTo(100.0, 10.0);

        path.lineTo(200.0, 150.0);
        path.lineTo(100.0, 200.0);

        canvas.drawPath(path, painter);
        break;
      case 'Besizerline2':
        Path path = new Path()..moveTo(0.0, 0.0);
        Rect rect1 = Rect.fromCircle(center: Offset(50.0, 100.0), radius: 60.0);
        path.arcTo(rect1, 0.0, 3.14, false);
        canvas.drawPath(path, painter);

        Rect rect2 = Rect.fromCircle(center: Offset(200.0, 100.0), radius: 60.0);
        path.arcTo(rect2, 0.0, 3.14*2, true);
        canvas.drawPath(path, painter);
        break;
      case 'Besizerline3':
        var width = size.width;
        var height = 300;
        Path path = new Path()..moveTo(width / 2, height / 4);
        path.cubicTo((width * 6) / 7, height / 9, (width * 13) / 13,
            (height * 2) / 5, width / 2, (height * 7) / 12);
        canvas.drawPath(path, painter
          // ..style = PaintingStyle.fill
          // ..color = Colors.red
        );

        Path path2 = new Path();
        path2.moveTo(width / 2, height / 4);
        path2.cubicTo(width / 7, height / 9, width / 21, (height * 2) / 5,
            width / 2, (height * 7) / 12);
        canvas.drawPath(path2, painter);
        break;
      case 'drawArc':
      // 绘制圆弧
      // Rect来确认圆弧的位置,还需要开始的弧度、结束的弧度、是否使用中心点绘制、以及paint弧度
        const PI = 3.1415926;
        Rect rect1 = Rect.fromCircle(center: Offset(size.width/2, 0.0), radius: 100.0);
        canvas.drawArc(rect1, 0.0, PI / 2, false, painter ..color = Colors.pink);

        Rect rect2 = Rect.fromCircle(center: Offset(size.width/2, 150.0), radius: 100.0);
        canvas.drawArc(rect2, 0.0, PI / 2, true, painter ..color = Colors.deepPurple);
        break;
      case 'drawRRect':
      /// fromPoints(Offset a, Offset b)
      /// 使用左上和右下角坐标来确定矩形的大小和位置
      /// fromCircle({ Offset center, double radius })
      /// 使用圆的圆心点坐标和半径和确定外切矩形的大小和位置
      /// fromLTRB(double left, double top, double right, double bottom)
      /// 使用矩形左边的X坐标、矩形顶部的Y坐标、矩形右边的X坐标、矩形底部的Y坐标来确定矩形的大小和位置
      /// fromLTWH(double left, double top, double width, double height)
      /// 使用矩形左边的X坐标、矩形顶部的Y坐标矩形的宽高来确定矩形的大小和位置
      // 用Rect构建一个边长50,中心点坐标为50,100的矩形
        Rect rect1 = Rect.fromCircle(center: Offset(50.0, 50.0), radius: 50.0);
        Rect rect2 = Rect.fromCircle(center: Offset(200.0, 50.0), radius: 50.0);
        // 根据上面的矩形,构建一个圆角矩形
        RRect rrect1 = RRect.fromRectAndRadius(rect1, Radius.circular(0.0));
        canvas.drawRRect(rrect1, painter);
        RRect rrect2 = RRect.fromRectAndRadius(rect2, Radius.circular(20.0));
        canvas.drawRRect(rrect2, painter);
        break;
      case 'drawDRRect':
      //绘制两个矩形
        Rect rect1 = Rect.fromCircle(center: Offset(size.width/2, 100.0), radius: 60.0);
        Rect rect2 = Rect.fromCircle(center: Offset(size.width/2, 100.0), radius: 40.0);
        //分别绘制外部圆角矩形和内部的圆角矩形
        RRect outer = RRect.fromRectAndRadius(rect1, Radius.circular(30.0));
        RRect inner = RRect.fromRectAndRadius(rect2, Radius.circular(5.0));
        canvas.drawDRRect(outer, inner, painter ..color = Colors.lime);
        break;
    }
  }

  ///控制自定义View是否需要重绘的,返回false代表这个View在构建完成后不需要重绘。
  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}