flutter 绘画

效果:

 

 

 实现:

import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

class CustomPaintPainterPage extends StatefulWidget {
  const CustomPaintPainterPage({Key? key}) : super(key: key);

  @override
  State<CustomPaintPainterPage> createState() => _CustomPaintPainterPageState();
}

class _CustomPaintPainterPageState extends State<CustomPaintPainterPage> {
  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const Text('基础理解', style: TextStyle(color: Colors.red)),
          const Text("    Paint:在画布上绘制时要使用的样式的描述(可描述为画笔)"),
          const Text("    Canvas:用于记录图形操作的界面(可描述为画布)"),
          const Text(
              "    Path:可以使用Canvas.drawPath在画布上绘制路径。并可用于使用Canvas.clipPath创建剪辑区域"),
          const SizedBox(height: 20),
          const Text("在flutter中并不是直接使用Paint、Canvas,而是使用进一步封装的widget,如下"),
          const Text(
              '官方https://api.flutter.dev/flutter/widgets/CustomPaint-class.html'),
          const Text('CustomPaint:', style: TextStyle(color: Colors.red)),
          const Text('    提供在绘制阶段绘制的画布,并利用CustomPainter来运行绘制指令的组件'),
          const Text('    它通常会将painter和child内嵌在其构造函数内:'),
          const Text('     painter是CustomPainter类的实例'),
          const Text('CustomPainter:', style: TextStyle(color: Colors.red)),
          const Text(
              '    CustomPaint(在widgets库中)和RenderCustomPaint(在渲染库中)使用的接口'),
          const Text('    画布绘制发生的地方'),
          const Text('    CustomPainter基类化,需要重写两个功能paint和shouldRepaint:'),
          const Text('    CustomPainter基类化,需要重写两个功能paint和shouldRepaint:'),
          const Text(
              '    paint方法是用于绘制的,它有两个参数Canvas和Size,所有的绘制指令应在指定大小的范围中发生;shouldRepaint它控制painter重绘的时间'),
          const SizedBox(
            height: 50,
          ),
          CustomPaint(
            foregroundPainter: MyPainter(),
            child: Container(
              color: Colors.blue,
              width: 600,
              height: 200,
            ),
          ),
          const SizedBox(
            height: 50,
          ),
          CustomPaint(
            foregroundPainter: SmilePainter(),
            child: Container(
              color: Colors.blue,
              width: 600,
              height: 200,
            ),
          ),
          const SizedBox(
            height: 50,
          ),
          CustomPaint(
            foregroundPainter: Sky(),
            child: Container(
              color: Colors.white,
              width: 600,
              height: 200,
            ),
          ),
          const SizedBox(
            height: 50,
          ),
          CustomPaint(
            painter: Sky(),
            child: const Center(
              child: Text(
                'Once upon a time...',
                style: TextStyle(
                  fontSize: 40.0,
                  fontWeight: FontWeight.w900,
                  color: Color(0xFFFFFFFF),
                ),
              ),
            ),
          ),
          const SizedBox(
            height: 50,
          ),
          CustomPaint(
            foregroundPainter: Pentagram(Colors.black),
            child: Container(
              color: Colors.blue,
              width: 200,
              height: 200,
            ),
          ),
        ],
      ),
    );
  }
}

class Pentagram extends CustomPainter {
  Pentagram(this.color);
  //画笔的颜色
  final Color color;

  @override
  void paint(Canvas canvas, Size size) {
    Offset getOffsetPosition(int degreen, double radius) {
      //角度转成弧度
      var radian = degreen * pi / 180;
      var dx = sin(radian) * radius;
      var dy = cos(radian) * radius;
      return Offset(dx + radius, dy + radius);
    }

    final paint = Paint()
      ..color = Colors.black
      ..style = PaintingStyle.fill;

    var initDegreen = 180;
    double radius = 100;
    // 连接五角星的五个顶点,360/5,每个是72度
    final path = Path();
    var posOne = getOffsetPosition(initDegreen, radius);
    var posTwo = getOffsetPosition(72 + initDegreen, radius);
    var posThree = getOffsetPosition(144 + initDegreen, radius);
    var posfour = getOffsetPosition(216 + initDegreen, radius);
    var posFive = getOffsetPosition(288 + initDegreen, radius);
    path.moveTo(posOne.dx, posOne.dy);
    path.lineTo(posfour.dx, posfour.dy);
    path.lineTo(posTwo.dx, posTwo.dy);
    path.lineTo(posFive.dx, posFive.dy);
    path.lineTo(posThree.dx, posThree.dy);
    //最后用close的方式把path封闭起来
    path.close();
    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    // TODO: implement shouldRepaint
    return false;
  }
}

class SmilePainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    const radius = 100.0;
    final center = Offset(size.width / 2.0, size.height / 2.0);
    final paint = Paint()..color = Colors.yellow;
    canvas.drawCircle(center, radius, paint);
    final smilePaint = Paint()
      ..style = PaintingStyle.stroke
      ..strokeWidth = 10;
    canvas.drawArc(Rect.fromCircle(center: center, radius: radius / 2), 0, pi,
        false, smilePaint);
    canvas.drawCircle(
        Offset(center.dx - radius / 2.0, center.dy - radius / 2.0),
        10,
        Paint());
    canvas.drawCircle(
        Offset(center.dx + radius / 2.0, center.dy - radius / 2.0),
        10,
        Paint());
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    // TODO: implement shouldRepaint
    return false;
  }
}

class Sky extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final Rect rect = Offset.zero & size;
    const RadialGradient gradient = RadialGradient(
      center: Alignment(0.7, -0.6),
      radius: 0.2,
      colors: <Color>[Color(0xFFFFFF00), Color(0xFF0099FF)],
      stops: <double>[0.4, 1.0],
    );
    canvas.drawRect(
      rect,
      Paint()..shader = gradient.createShader(rect),
    );
  }

  @override
  SemanticsBuilderCallback get semanticsBuilder {
    return (Size size) {
      // Annotate a rectangle containing the picture of the sun
      // with the label "Sun". When text to speech feature is enabled on the
      // device, a user will be able to locate the sun on this picture by
      // touch.
      Rect rect = Offset.zero & size;
      final double width = size.shortestSide * 0.4;
      rect = const Alignment(0.8, -0.9).inscribe(Size(width, width), rect);
      return <CustomPainterSemantics>[
        CustomPainterSemantics(
          rect: rect,
          properties: const SemanticsProperties(
            label: 'Sun',
            textDirection: TextDirection.rtl,
          ),
        ),
      ];
    };
  }

  @override
  bool shouldRepaint(Sky oldDelegate) => false;
  @override
  bool shouldRebuildSemantics(Sky oldDelegate) => false;
}

class MyPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    Paint onePaint = Paint()
      ..style = PaintingStyle.fill // 是否填充
      ..color = Colors.red
      ..strokeWidth = 3;
    Paint twoPaint = Paint()
      ..style = PaintingStyle.stroke // 是否填充
      ..color = Colors.white
      ..strokeWidth = 3;
    // canvas.drawPaint(newPaint);
    canvas.drawCircle(const Offset(75, 95), 50, onePaint);
    canvas.drawLine(const Offset(70, 30), const Offset(170, 30), onePaint);
    canvas.drawRect(
        Rect.fromPoints(const Offset(140, 80), const Offset(190, 60)),
        onePaint);
    canvas.drawCircle(const Offset(275, 95), 50, twoPaint);
    canvas.drawLine(const Offset(270, 30), const Offset(370, 30), twoPaint);
    canvas.drawRect(
        Rect.fromPoints(const Offset(340, 80), const Offset(390, 60)),
        twoPaint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    // TODO: implement shouldRepaint
    return false;
  }
}

 

posted @ 2022-05-26 14:22  Belinda_sl  阅读(129)  评论(0编辑  收藏  举报