我是靠谱客的博主 俊逸花瓣,最近开发中收集的这篇文章主要介绍Flutter绘制系列03---绘制图片文字2、 文字绘制,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

在这里插入图片描述

1、绘制图片系列

因为读取图片是一个异步的操作,在读取完毕之后,需要重新渲染界面,也就是可变状态。现在要有一个概念:画布只承担绘制工作,一切数据的来源由使用者来提供。也就是将ui.Image对象作为参数传递給PaperPainter,画板质询要关注于操作。

class Paper extends StatefulWidget {
  @override
  _PaperState createState() => _PaperState();
}

class _PaperState extends State<Paper> {
  ui.Image? _image;

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

  void _loadImage() async {
    _image =
        await loadImageFromAssets('assets/images/wy_300x200.jpg');
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    return Container(
        color: Colors.white, 
        child: CustomPaint(painter: PaperPainter(_image)));
  }

  // 方法在上面已给出,不再重复书写...
  //读取 assets 中的图片
  Future<ui.Image>? loadImageFromAssets(String path) async {
    ByteData data = await rootBundle.load(path);
    return decodeImageFromList(data.buffer.asUint8List());
  }
}

好,这样我们就将一个画板创造出来了。并且上面会有一张我们drawImage出来的图片。
在这里插入图片描述
好的,这样的话我们的图片就成功的在画布上渲染出来了。然后我们再来思考一个问题,我们有没有可能将这个图片给他按照矩形裁剪出来呢?

void _drawImageRect(Canvas canvas) {
    if (image != null) {
      canvas.drawImageRect(
          image!,
          Rect.fromCenter(
              center: Offset(image!.width/2, image!.height/2), width: 60, height: 60),
          Rect.fromLTRB(0, 0, 100, 100).translate(200, 0),
          _paint);

      canvas.drawImageRect(
          image!,
          Rect.fromCenter(
              center: Offset(image!.width/2, image!.height/2-60), width: 60, height: 60),
          Rect.fromLTRB(0, 0, 100, 100).translate(-280, -100),
          _paint);

      canvas.drawImageRect(
          image!,
          Rect.fromCenter(
              center: Offset(image!.width/2+60, image!.height/2), width: 60, height: 60),
          Rect.fromLTRB(0, 0, 100, 100).translate(-280, 50),
          _paint);
    }
  }

这样,我们就可以将我们的图片做各种不同的裁剪绘制了。
在这里插入图片描述

4、图片域绘制

drawImageNine中主要是两个矩形区域,center和dst。center表示从资源图片image上一块可缩放的矩形域,所以原点是图片的左上角。dst表示将扣出的图片填充到画布的哪个矩形域当中去。所以圆点是画布原点。这样很容易画出气泡的效果。即指定区域进行缩放,其余不动。

在这里插入图片描述

void _drawImageNine(Canvas canvas) {
    if (image != null) {
      canvas.drawImageNine(
          image!,
          Rect.fromCenter(center: Offset(image!.width/2, image!.height-6.0),
              width: image!.width-20.0, height: 2.0),
          Rect.fromCenter(center: Offset(0, 0,), width:300, height: 120),
          _paint);

      canvas.drawImageNine(
          image!,
          Rect.fromCenter(center: Offset(image!.width/2, image!.height-6.0),
              width: image!.width-20.0, height: 2.0),
          Rect.fromCenter(center: Offset(0, 0,), width:100, height: 50).translate(250, 0),
          _paint);

      canvas.drawImageNine(
          image!,
          Rect.fromCenter(center: Offset(image!.width/2, image!.height-6.0),
              width: image!.width-20.0, height: 2.0),
          Rect.fromCenter(center: Offset(0, 0,), width:80, height: 250).translate(-250, 0),
          _paint);
    }
  }

5、绘制图集drawAtlas

这个方法有7个参数,用起来比较复杂,主要作用是,在画布上绘制一张图片的很多部分,比如雪碧图(Sprite)将需要的图片放在一张图里面。另外通过drawAtlas绘制的效率更加的高

  • 定义每个Sprite类封装图片元素数据
class Sprite{
 // 矩形区域
 Rect position;
 // 距离中心点偏移
 Offset? offset;
 // 透明度
 int? alpha;
 // 旋转角度
 double rotation;
 Sprite({this.offset, this.alpha, this.rotation = 0, required this.position});
}
  • 绘制一张图片

绘制时必须要传入的参数是,图片 ui.Image变换列表List<RSTransform>矩形列表List<Rect>,下面通过矩形域就可以绘制这张图片:
在这里插入图片描述

void _drawSprite(Canvas canvas){
    // 添加一个 Sprite
    allSprites.add(Sprite(
        position: Rect.fromLTWH(0, 325, 257, 166),
        offset: Offset(0, 0),
        alpha: 255,
        rotation: 0));
    // 通过 allSprites 创建 RSTransform 集合
    final List<RSTransform> transforms = allSprites
        .map((sprite) => RSTransform.fromComponents(
      rotation: sprite.rotation,
      scale: 1.0,
      anchorX: 0,
      anchorY: 0,
      translateX: sprite.offset!.dx,
      translateY: sprite.offset!.dy,
    ))
        .toList();
    // 通过 allSprites 创建 Rect 集合
    final List<Rect> rects =
    allSprites.map((sprite) => sprite.position).toList();

    canvas.drawAtlas(image!, transforms, rects, null, null, null, _paint);
  }
  • 图形的变换

我们在定义Sprite时,可以将变化的属性放在其中,如平移,缩放,透明度等。一般雪碧图制作工具都会给出图片在大图中的坐标位置信息,可以添加解析到allSprites中去。
除此之外的还有颜色Color,混合模式blendMode,据此你可以对图片进行更多的操作。

5、绘制原始图集:drawAtlas

这个方法是drawAtlas的底层实现,其中变换列表,矩形域列表都转化为Float32List,颜色数组转化为Int32List,在使用方法上是一致的。

void _drawColorfulImage(Canvas canvas){
    allSprites.add(Sprite(
        position: Rect.fromLTWH(0, 325, 257, 166),
        offset: Offset(0, 0),
        alpha: 255,
        rotation: 0));

    allSprites.add(Sprite(
        position: Rect.fromLTWH(0, 325, 257, 166),
        offset: Offset(257, 130),
        alpha: 255,
        rotation: 0));

    Float32List rectList = Float32List(allSprites.length * 4);
    Float32List transformList = Float32List(allSprites.length * 4);

    for (int i = 0; i < allSprites.length; i++) {
      final Sprite sprite = allSprites[i];
      rectList[i * 4 + 0] = sprite.position.left;
      rectList[i * 4 + 1] = sprite.position.top;
      rectList[i * 4 + 2] = sprite.position.right;
      rectList[i * 4 + 3] = sprite.position.bottom;
      final RSTransform transform = RSTransform.fromComponents(
        rotation: sprite.rotation,
        scale: 1.0,
        anchorX: sprite.anchor.dx,
        anchorY: sprite.anchor.dy,
        translateX: sprite.offset!.dx,
        translateY: sprite.offset!.dy,
      );
      transformList[i * 4 + 0] = transform.scos;
      transformList[i * 4 + 1] = transform.ssin;
      transformList[i * 4 + 2] = transform.tx;
      transformList[i * 4 + 3] = transform.ty;
    }
    canvas.drawRawAtlas(image!, transformList, rectList, null, null, null, _paint);
  }

2、 文字绘制

Flutter里面的文字绘制方法明显要麻烦很多,但属性多也就意味着可定制性高
主要的绘制方法是通过drawParagraphTextPaint.

在这里插入图片描述

1、drawParagraph绘制文字

通过ParagraphBuilder构造基本样式pushStyle和添加文字addText.builder.build()可以创建Paragraph对象,之后必须对layout限制区域,下面的蓝色区域是绘制的辅助,依次是左对齐、居中、右对齐。

void _drawTextWithParagraph(Canvas canvas,TextAlign textAlign) {
    var builder = ui.ParagraphBuilder(ui.ParagraphStyle(
      textAlign: textAlign,
      fontSize: 40,
      textDirection: TextDirection.ltr,
      maxLines: 1,
    ));
    builder.pushStyle(
      ui.TextStyle(
          color: Colors.black87, textBaseline: ui.TextBaseline.alphabetic),
    );
    builder.addText("Flutter Unit");
    ui.Paragraph paragraph = builder.build();
    paragraph.layout( ui.ParagraphConstraints(width: 300));
    canvas.drawParagraph(paragraph, Offset(0, 0));
    canvas.drawRect(Rect.fromLTRB(0, 0, 300, 40 ),
        _paint..color = Colors.blue.withAlpha(33));
  }

在这里插入图片描述

2、TextPainter绘制文字

TextPainter的绘制基本上就是对drawParagraph的封装,但是提供了很多的方法,使用起来更加简介一点,所以一般来说都会用TextPainter绘制文字。绘制先传入的TextPainter,然后进行layout布局,其中可以传入布局区域的最大和最小宽度,通过paint方法进行绘制。

void _drawTextPaint(Canvas canvas) {
    var textPainter = TextPainter(
        text: TextSpan(
            text: 'Flutter Unit',
            style: TextStyle(fontSize: 40,color: Colors.black)),
        textAlign: TextAlign.center,
        textDirection: TextDirection.ltr);
    textPainter.layout(); // 进行布局
    textPainter.paint(canvas, Offset.zero); // 进行绘制
  }

在这里插入图片描述

最后

以上就是俊逸花瓣为你收集整理的Flutter绘制系列03---绘制图片文字2、 文字绘制的全部内容,希望文章能够帮你解决Flutter绘制系列03---绘制图片文字2、 文字绘制所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(60)

评论列表共有 0 条评论

立即
投稿
返回
顶部