Flutter Canvas 进阶教程 (二)

2021/7/26 flutter

# 简单的canvas 绘画面板

import 'package:flutter/material.dart';

const Color pintColorDefault = Color(0xFFB275F5);

const Map<String, Color> pintColor = {
  'default': Color(0xFFB275F5),
  'black': Colors.black,
  'brown': Colors.brown,
  'gray': Colors.grey,
  'blueGrey': Colors.blueGrey,
  'blue': Colors.blue,
  'cyan': Colors.cyan,
  'deepPurple': Colors.deepPurple,
  'orange': Colors.orange,
  'green': Colors.green,
  'indigo': Colors.indigo,
  'pink': Colors.pink,
  'teal': Colors.teal,
  'red': Colors.red,
  'yellow': Colors.yellow,
  'purple': Colors.purple,
  'blueAccent': Colors.blueAccent,
  'white': Colors.white,
};

class DrawingBoardModel {
  DrawingBoardModel({
    this.offset,
    this.strokeWidth = 3.0,
    this.color = const Color(0xFFB275F5),
  });

  final Offset? offset;
  final Color color;
  final double strokeWidth;
}

class DrawingBoard extends CustomPainter {
  DrawingBoard({required this.offsetList}) {
    _paint = Paint()
      ..color = Colors.amberAccent
      ..strokeCap = StrokeCap.round
      ..isAntiAlias = true
      ..strokeWidth = 3.0
      ..style = PaintingStyle.stroke
      ..blendMode = BlendMode.srcOver
      ..strokeJoin = StrokeJoin.bevel;
  }

  List<DrawingBoardModel?> offsetList;
  late Paint _paint;

  
  void paint(Canvas canvas, Size size) {
    for (int i = 0; i < offsetList.length - 1; i++) {
      if (offsetList[i]?.offset != null && offsetList[i + 1]?.offset != null) {
        // canvas.restore();
        _paint
          ..color = offsetList[i]!.color
          ..strokeWidth = offsetList[i]!.strokeWidth;

        canvas.drawLine(
            offsetList[i]!.offset!, offsetList[i + 1]!.offset!, _paint);
        // canvas.save();
      }
    }
  }

  
  bool shouldRepaint(DrawingBoard oldDelegate) {
    return oldDelegate.offsetList == offsetList;
  }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

你画我猜 实现

  1. 需要考虑多指触碰.

  2. 否则会导致绘画过程帧率卡的飞起问题.面板需要 构建两层canvas画布 表层用来绘制不保留绘制在画布上的绘制的坐标数据,当手指松开时 释放数据并添加到绘制坐标数组 然后通知底层canvas画布把数组数据渲染出来

# 贝塞尔曲线

  • 底部波浪剪切

import 'dart:ui';
import 'package:flutter/widgets.dart';

class BottomClipper extends CustomClipper<Path> {
  const BottomClipper({
    this.y1 = 40,
    this.y2 = 30,
    this.y3 = 90,
  });
  final double y1;
  final double y2;
  final double y3;

  
  Path getClip(Size size) {
    var path = Path();

    path.lineTo(0, 0);
    path.lineTo(0, size.height - y1);

    var firstPoint = Offset(size.width / 4, size.height);
    var secondPoint = Offset(size.width / 2.25, size.height - y2);
    path.quadraticBezierTo(
        firstPoint.dx, firstPoint.dy, secondPoint.dx, secondPoint.dy);

    var thirdPoint = Offset(size.width / 4 * 3, size.height - y3);
    var fourthPoint = Offset(size.width, size.height - y1);

    path.quadraticBezierTo(
        thirdPoint.dx, thirdPoint.dy, fourthPoint.dx, fourthPoint.dy);

    path.lineTo(size.width, 0);
    return path;
  }

  
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    return false;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
  • 底部弧形剪切
import 'dart:ui';
import 'package:flutter/widgets.dart';
class BottomArcClipper extends CustomClipper<Path> {
  
  Path getClip(Size size) {
    var path = Path();
    double? _py = 50.0;

    path.lineTo(0, size.height - _py);

    var firstPoint = Offset(size.width / 4, size.height);
    var endPoint = Offset(size.width / 2, size.height);

    path.quadraticBezierTo(
        firstPoint.dx, firstPoint.dy, endPoint.dx, endPoint.dy);

    var firstPoint2 = Offset(size.width - (size.width / 4), size.height);
    var endPoint2 = Offset(size.width, size.height - _py);

    path.quadraticBezierTo(
        firstPoint2.dx, firstPoint2.dy, endPoint2.dx, endPoint2.dy);

    path.lineTo(size.width, 0);
    path.close();
    return path;
  }

  
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    return false;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Last Updated: 2021/8/11 12:02:21