• 【Flutter学习】之绘画实例(二)


    一,画路径 - drawPath(Path path, Paint paint)  

      Path 主要有方法如下:

      直接描述路径的方法还可以细分为两组:添加子图形和画线(直线或曲线)

    • addXXX() - 添加子图形(由于此类方法参数与上面介绍的画简单图形一样,就不多赘述了)

    1. addArc(Rect oval, double startAngle, double sweepAngle) - 添加圆弧
    2. addOval(Rect oval) - 添加圆
    3. addPolygon(List<Offset> points, bool close) - 添加一个由点的集合描述的多边形
    4. addRect(Rect rect) - 添加矩形
    5. addRRect(Rect rect) - 添加圆角矩形
    6. addPath(Path path, Offset offset) - 添加子路径
    • XXXTo() - 画线(直线或曲线)

      这个方法通过描述路径的方式来绘制图形,用法大概是这样:

     Path _path = Path();
      @override
      void paint(Canvas canvas, Size size) {
        _paint.style = PaintingStyle.stroke; // 画线模式
        _path.addArc(new Rect.fromLTWH(50, 50, 50, 50), 135.0 * (pi / 180.0), 225.0 * (pi / 180.0));
        _path.addArc(new Rect.fromLTWH(100, 50, 50, 50), 180.0 * (pi / 180.0), 225.0 * (pi / 180.0));
        _path.lineTo(100, 140);
        _path.lineTo(58, 93);
        canvas.drawPath(_path, _paint);
      }

    • 向目标位置画直线 - lineTo(double x, double y) / relativelineTo(double x, double y)
      当前位置向目标位置画一条直线, x 和 y 是目标位置的坐标。这两个方法的区 别是, lineTo(x, y) 的参数是绝对坐标,而 relativeLineTo(x, y) 的参数是相对当前位置相对坐标 ;

    • _paint.style = PaintingStyle.stroke; // 画线模式
      _path.lineTo(100, 100); // 由当前位置 (0, 0) 向 (100, 100) 画一条直线
      _path.relativeLineTo(100, 0); // 由当前位置 (100, 100) 向正右方画100像素的位置
      canvas.drawPath(_path, _paint);

    • 画二阶贝塞尔曲线 - quadraticBezierTo(double x1, double y1, double x2, double y2) /  relativeQuadraticBezierTo(double x1, double y1, double x2, double y2) 

      x1,y1是控制点的坐标;x2,y2是结束点的坐标;relativeQuadraticBezierTo()同上面相对直线方法

      _paint.style = PaintingStyle.stroke; // 画线模式
      List<Offset> points = new List();
      points.add(new Offset(100, 50)); // 画出控制点位置,方便理解
      canvas.drawPoints(PointMode.points, points, _paint);
      _path.moveTo(0, 100); // 移动起点到(0,100)
      _path.quadraticBezierTo(100, 50, 200, 100);
      canvas.drawPath(_path, _paint);

    • 画三阶贝塞尔曲线 - cubicTo(double x1, double y1, double x2, double y2, double x3, double y3) / relativeCubicTo(double x1, double y1, double x2, double y2, double x3, double y3) 

      和上面这个 quadraticBezierTo()和relativeQuadraticBezierTo() 的二阶贝塞尔曲线同理,就不多说了。

       @override
        void paint(Canvas canvas, Size size) {
            
         Path path = new Path()..moveTo(100.0, 100.0);
          List<Offset> points = new List();
          points.add(new Offset(100, 50)); // 画出控制点位置,方便理解
          canvas.drawPoints(PointMode.points, points, _paint);
          path.moveTo(0, 100); // 移动起点到(0,100)
          path.cubicTo(100, 100, 200, 200, 300, 300);
          canvas.drawPath(path, _paint);
        }

    • 移动到某点 - moveTo(double x, double y) / relativeMoveTo(double dx, double dy) 

      不论是直线还是贝塞尔曲线,都是以当前位置作为起点,而不能指定起点。但可以通过 moveTo(x, y) 或 relativeMoveTo(x, y) 来改变当前位置,从而间接地设置这些方法的起点。

      _paint.style = PaintingStyle.stroke; // 画线模式
      _path.moveTo(20, 40); // 移动起点到(20,40)
      _path.lineTo(80, 100); // 画条斜线
      _path.moveTo(100, 40); // 移动起点到(100,20)
      _path.lineTo(100, 100); // 画条直线
      canvas.drawPath(_path, _paint);

      但凡事都有例外 arcTo() 这个方法并不从当前位置开始绘制

    • 画弧线 - arcTo(Rect rect, double startAngle, double sweepAngle, bool forceMoveTo) 

      前三个参数,我们已经很熟悉了,最后一个参数的意思是,画这个弧的时候是拖着笔到起点还是抬下笔到起点

      _paint.style = PaintingStyle.stroke; // 画线模式
      _path.moveTo(20, 40); // 移动起点到(20,40)
      _path.lineTo(80, 100); // 画条斜线
      _path.arcTo(new Rect.fromLTWH(60, 60, 100, 100), 0.0 * (pi / 180.0), 90.0 * (pi / 180.0), false);
      canvas.drawPath(_path, _paint);

      拖着笔:

      抬下笔:

    • 封闭当前路径 - close() 

      _paint.style = PaintingStyle.stroke; // 画线模式
      _path.moveTo(20, 40); // 移动起点到(20,20)
      _path.lineTo(80, 100); // 画条斜线
      _path.arcTo(new Rect.fromLTWH(60, 60, 100, 100), 0.0 * (pi / 180.0), 90.0 * (pi / 180.0), false);
      _path.close(); // 封闭当前路径
      canvas.drawPath(_path, _paint);

      到这里Canvas图形的绘制就讲的差不多了,图形简单时,使用 drawCircle() drawRect() 等方法来直接绘制;图形复杂时,使用 drawPath() 来绘制自定义图形。 除此之外, Canvas 还可以绘制图片和文字。

    二,画图片 - drawImage(Image image, Offset p, Paint paint) / drawImageRect(Image image, Rect src, Rect dst, Paint paint) 

    • 系统方法

      drawImage() 从指定点开始将图片宽高按像素绘制,由于无法控制图片的大小,并不常用;第一个参数是ui包下的Image,并不是Image Widge

    • 使用方法

      Image 可以通过以下代码获取

      ui.Image image;
      /**
       * 初始化图片
       *
        Future<VoidCallback> initImage() async {
          image = await _loadImage("./assets/images/img.jpg");
          return null;
        }
      
        /**
         * 通过assets路径,获取资源图片
         */
        Future<Image> _loadImage(String assets) async {
          final ByteData data = await rootBundle.load(assets);
          if (data == null) throw 'Unable to read data';
          Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List());
          FrameInfo frame = await codec.getNextFrame();
          return frame.image;
        }

      然后在initState() 方法中初始化(  shouldRepaint() 方法一定要记得返回 true  ,否则无法重绘

      void initState() {
        super.initState();
        painter.initImage().then((val) {
          setState(() {
          });
        });
      }

      最后在 paint() 方法中填入以下代码:

      canvas.drawImage(image, new Offset(0, 0), _paint);

      drawImageRect() 这个方法经常使用;主要了解第二个参数与第三个参数:

      • Rect src - 原图的区域,一般传图片的宽高
      • Rect dst - 显示的区域, 指图片显示的区域,如果原图区域宽高比与显示区域不一致,原图会被拉伸压缩
      canvas.drawImageRect(image, Offset(0.0, 0.0) & Size(image.width.toDouble(), image.height.toDouble()), Offset(0.0, 0.0) & Size(200, 200), _paint);

      正常比例:

      拉伸:

    三,画文字 - drawParagraph(Paragraph paragraph, Offset offset)

    • 系统方法

      drawParagraph(Paragraph paragraph, Offset offset)
    • 使用方法

      代码注释的很清楚,这里循环画了5段文字

      for (int i = 0; i<5 ;i++){
        // 新建一个段落建造器,然后将文字基本信息填入;
        ParagraphBuilder pb = ParagraphBuilder(ParagraphStyle(
          textAlign: TextAlign.left,
          fontWeight: FontWeight.w300,
          fontStyle: FontStyle.normal,
          fontSize: 15.0+i,
        ));
        pb.pushStyle(ui.TextStyle(color: Colors.black87));
        pb.addText('Flutter一统移动端');
        // 设置文本的宽度约束
        ParagraphConstraints pc = ParagraphConstraints( 300);
        // 这里需要先layout,将宽度约束填入,否则无法绘制
        Paragraph paragraph = pb.build()..layout(pc);
        // 文字左上角起始点
        Offset offset = Offset(50, 50+i*40.0);
        canvas.drawParagraph(paragraph, offset);
      }
    • 示例

     

    参考:https://juejin.im/post/5c67a6a0f265da2dae510fa2#heading-14

  • 相关阅读:
    《第一行代码》阅读笔记(十四)——ViewPager
    《第一行代码》阅读笔记(十三)——碎片的最佳案例
    《第一行代码》阅读笔记(十二)——探究碎片
    《第一行代码》阅读笔记(十一)——编写界面的最佳案例
    《第一行代码》阅读笔记(十)——RecyclerView
    《第一行代码》阅读笔记(九)——ListView
    《第一行代码》阅读笔记(八)——自定义控件
    《第一行代码》阅读笔记(七)——Android经典四种布局
    《第一行代码》阅读笔记(六)——AndroidUI控件(初级)
    后台管理系统左侧菜单栏显示隐藏
  • 原文地址:https://www.cnblogs.com/lxlx1798/p/11261737.html
Copyright © 2020-2023  润新知