如何优雅地画一张图

作者:不近视的猫
转载地址:https://juejin.cn/post/7105110185768648711

前言

在 Flutter 中,若我们需要自定义画一张图,则需要用到 CustomPaint,不过 CustomPaint 并不是本篇文章的重点,所以我就直接贴出 CustomPaint 的相关代码,保证能够正常绘制即可。

class MyHomePage extends StatefulWidget {const MyHomePage({Key? key}) : super(key: key);@overrideState<MyHomePage> createState() => _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {@overrideWidget build(BuildContext context) {return Container(color: Colors.white,child: CustomPaint(painter: MyPainter(),),);}
}

class MyPainter extends CustomPainter {@overridevoid paint(Canvas canvas, Size size) {canvas.drawRect(const Rect.fromLTRB(50, 50, 200, 200), Paint());}@overridebool shouldRepaint(covariant CustomPainter oldDelegate) {return false;}
}

绘制的效果:

其中,最核心的绘制在 MyPainterpaint(Canvas canvas, Size size) 中。

获取图片

我们可以看到,canvas 绘制图片有三种方式:

他们都有一个核心共同点,那就是需要绘制的图片数据,但是这个 Image 并不是我们经常在 UI 效果上写的 widgets.Image,而是 ui.Image,所以获取图片数据的方式就不太一样。

在这里我封装了一个图片转换工具:

enum ImageType{net, file, asset
}class ImageUtils {/// 获取图片static Future<ui.Image> loadImage(String path, ImageType type) async {// 根据图片的路径转为 ImageStreamImageStream stream;switch(type){case ImageType.net:stream = NetworkImage(path).resolve(ImageConfiguration.empty);break;case ImageType.file:stream = FileImage(File(path)).resolve(ImageConfiguration.empty);break;case ImageType.asset:stream = ExactAssetImage(path).resolve(ImageConfiguration.empty);break;}// 添加转换监听Completer<ui.Image> completer = Completer<ui.Image>();void listener(ImageInfo frame, bool synchronousCall) {final ui.Image image = frame.image;completer.complete(image);stream.removeListener(ImageStreamListener(listener));}stream.addListener(ImageStreamListener(listener));return completer.future;}
}

支持转换网络图片、文件图片、Asset 中的图片,只需要传入图片路径和图片的类型即可。

另外,转换的逻辑也比较简单,只是把不同类型的图片转为 ImageStream,同时给 ImageStream 添加转换结束的监听,然后把 future 进行返回,所以,这是一个异步操作。下面,我们来具体写写:

import 'dart:ui' as ui;class MyHomePage extends StatefulWidget {const MyHomePage({Key? key}) : super(key: key);@overrideState<MyHomePage> createState() => _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {ui.Image? _image;@overridevoid initState() {super.initState();ImageUtils.loadImage("images/wuliannan.jpg", ImageType.asset).then((value) {setState(() {_image = value;});});}@overrideWidget build(BuildContext context) {return _image == null? Container(): Container(color: Colors.white,child: CustomPaint(painter: MyPainter(_image!),),);}
}

代码也比较简单,也就是在 initState() 中异步获取数据,然后将其传给 MyPainter,然后我们在 MyPainter 中进行绘制:

class MyPainter extends CustomPainter {const MyPainter(this._image): super();final ui.Image _image;@overridevoid paint(Canvas canvas, Size size) {canvas.drawImage(_image, Offset(0,100), Paint());}@overridebool shouldRepaint(covariant CustomPainter oldDelegate) {return false;}
}

效果:

绘图

刚刚我们也提到过,在 canvas 中绘制图片有三种方式:

  • drawImage
  • drawImageRect
  • drawImageNine

drawImage

void drawImage(Image image, Offset offset, Paint paint)

主要就是 Offset 参数,也就是在绘制图片确定图片的开始位置,这个绘制图片方式并没有约束图片的大小,所以总体来说,就是指定图片左上角,然后绘制原图。

canvas.drawImage(_image, Offset(200,100), Paint());

效果:

drawImageRect

drawImageRect(Image image, Rect src, Rect dst, Paint paint)

主要参数为 Rect srcRect dst

  • src:裁剪原图,矩形位置大小,就是裁剪的位置大小。
  • sdt:将裁剪后的图片展示到画布的位置和大小,若大小跟裁剪的大小不一致,则会直接拉伸。
    canvas.drawImageRect(_image, Rect.fromLTRB(50, 50, 500, 500),Rect.fromLTRB(50, 50, 300, 300), Paint());

效果:

drawImageNine

drawImageNine(Image image, Rect center, Rect dst, Paint paint)

这种绘图方式有些特别,很多人都会将其理解为平均拆分的九宫格,其实并不是的,它其实更符合 .9 的做法。

我们在制作 .9 图的时候,我们需要设置可拉伸的区域:

我们可以看到,左图中被颜色覆盖的区域就是可拉伸区域,当其需要被拉伸的时候,这块区域就会被拉伸,就像右图那样脸被拉宽了,但是音符并没有变形,所以,drawImageNine 中的 Rect center 其实描述的就是左图中的被紫色覆盖的区域,而 Rect dst 其实就是把图片放到 dst 的区域,但是原图不一定跟 dst 区域保持一致,这时就好拉伸,而拉伸的区域就是上述讲的左图被颜色覆盖的区域,并不是指紫色那块区域。

这里,我们通过 Rect.fromCenter 来设置中心区域:

    final centerRect = Rect.fromCenter(center: Offset(_image.width / 2, _image.height / 2),width: 100,height: 100);canvas.drawImageNine(_image, centerRect,Rect.fromLTRB(50, 50, 300, 300), Paint());

效果:

我们可以看到,中间区域被压缩没了,但是被拉伸后的图片还是比 dst 区域大,然后它就把压缩后的图片再次拉伸为 dst 区域的大小。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/62639.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

chatgpt赋能python:使用Python建立数据库

使用Python建立数据库 在当今的数字时代&#xff0c;数据是无处不在的。企业、政府甚至个人都需要存储和管理他们的数据以支持他们的工作。数据库就成为了一个必不可少的工具。在本文中&#xff0c;我们将介绍如何使用Python来创建数据库。 什么是数据库&#xff1f; 一个数…

盘点一个Python网络爬虫问题

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 在天愿作比翼鸟&#xff0c;在地愿为连理枝。 大家好&#xff0c;我是皮皮。 一、前言 前几天在Python最强王者群【刘桓鸣】问了一个Python网络爬虫的问…

请问这个网址怎么用httpx 把json数据取出来

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 空山新雨后&#xff0c;天气晚来秋。 大家好&#xff0c;我是皮皮。 一、前言 前几天在Python铂金群【gyx】问了一个Python网络爬虫处理的问题&#xf…

大伙,为啥我爬虫爬百度搜索得出的结果是0啊?

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 君王掩面救不得&#xff0c;回看血泪相和流。 大家好&#xff0c;我是皮皮。 一、前言 前几天在Python白银交流群【~Crazy】问了一个Python网络爬虫处理…

Python网络爬虫,我目前只能获取单个文件,为啥?

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 归来池苑皆依旧&#xff0c;太液芙蓉未央柳。 大家好&#xff0c;我是皮皮。 一、前言 前几天在Python钻石交流群【Jethro Shen】问了一个Python网络爬…

盘点一个Python网络爬虫过验证码的问题(方法一)

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 低眉信手续续弹&#xff0c;说尽心中无限事。 大家好&#xff0c;我是皮皮。 一、前言 前几天在Python最强王者群【鶏啊鶏。】问了一个Python网络爬虫的…

小红书怎么推广笔记?小红书推广笔记有什么用?

小红书平台问世以来&#xff0c;得到快速发展&#xff0c;目前已经是电商领域的后起之秀&#xff0c;也是重要的口碑平台&#xff0c;在女性及生活用品方面的影响力不次于微信和微博&#xff0c;可以说是和抖音齐名的新秀平台。大家都知达到小红书平台的重要重要性&#xff0c;…

小红书笔记下沉的方法和技巧

小红书目前用户越来越多&#xff0c;随之而来发布的笔记数量也大了起来&#xff0c;不可避免得出现很多恶意的负面笔记&#xff0c;让大家很头疼。 下面推神网&#xff08;daizuobaike&#xff09;就给大家详细介绍下几种小红书负面笔记处理的方式: 1.官方入口&#xff0c;达到…

3.13 小红书笔记怎样带话题,才能增加曝光?【玩赚小红书】

虽然很多博主都知道在笔记内容最后要带上一个相关话题&#xff0c;但却很少人知道带什么样的话题&#xff0c;如何找到官方话题或热门话题来提高笔记内容的曝光。这一篇文章黄宇风就来讲讲&#xff0c;小红书笔记该如何带话题。 ​ ​ 1、挖掘小红书笔记热门话题 笔记带话题主…

小红书笔记没人看是什么原因?账号正常吗

相信很多人都遇到过自己认为笔记质量不错&#xff0c;但仍然会出现发布的小红书笔记没人看的情况。我们将为大家分析可能是哪些原因造成了这方面的困境&#xff0c;并告诉大家应该如何解决这些问题。 一&#xff0e;小红书笔记没人看的原因 1.账号违规 如果账号本身昵称、个性…

小红书怎样找回原账号_小红书笔记数据好不好,关键词搜索占一半

用户获取、浏览小红书笔记的渠道大致可以分为四个&#xff0c;一个是关注的博主账号&#xff0c;首页会有他们的笔记内容推荐;一个是主页上的发现页面&#xff0c;会推荐平常该用户感兴趣的内容以及附近地点的笔记;另外还有的则是小红书系统推荐。但更多小红书用户平常看笔记、…

小红书笔记打开显示连接不到服务器,小红书笔记看不到全文怎么回事啊?怎么发布小红书笔记?...

我们可以通过小红书购物笔记了解一些商品哦&#xff0c;因为小红书购物笔记里面的内容基本都是一些买家的购物体验&#xff0c;对于要买东西的我们来说&#xff0c;可以提供一些建议。可是最近有网友咨询小红书笔记看不到全文&#xff0c;小红书购物笔记找不到怎么回事?怎么发…

与领导吃饭需要注意什么

虽然说招待客人需要一定的技巧&#xff0c;但不是所有的聚餐&#xff0c;对方都会答应宴请&#xff1b;尤其是下属请领导吃饭时&#xff0c;不仅需要各种礼仪&#xff0c;还需要一定的技巧&#xff1b;当领导遇到下属&#xff0c;要请客吃饭时&#xff0c;都认为下属是有目的的…

新来的领导把我的职务免掉了,一年后,我要不要找领导聊聊?

你这一年都不找领导聊&#xff0c;现在人家另外两个都官复原职了&#xff0c;你才想起来聊聊&#xff0c;晚了。 从你的叙述中可以看出&#xff0c;你是一个非常正直的人&#xff0c;要不然被免职后也不会这么干等着。但正是你的正直&#xff0c;才导致了复职的是另外两个 &am…

领导找你谈话要注意这些

我的朋友小单每天努力工作&#xff0c;得到领导的重视&#xff1b;有一次小单正在认真工作&#xff0c;领导突然把小单叫到办公室谈话。小单一开始还有些紧张&#xff0c;没想到领导正好找她谈心&#xff0c;小单明白了领导的目的后就开口说话了。领导表面上只是问&#xff0c;…

如何看待程序员休息时间不工作被领导威胁辞退的?

在现在的互联网行业&#xff0c;程序员在职场工作肯定是十分辛苦的&#xff0c;基本很多公司都是996制度&#xff0c;这也和互联网行业工作环境有关系。因此程序员基本就只有周末一天假&#xff0c;所以难得休息一下。就有一名程序员因为在休息时间不工作被领导威胁辞退&#x…

程序员被领导辞退,1周后接到领导电话,听完后网友:把他拉黑

员工离职后&#xff0c;跟原来的单位就不再是雇佣关系&#xff0c;如果原单位有事情需要员工帮着解决&#xff0c;员工该不该收取报酬呢&#xff0c;但有的老板却认为&#xff0c;员工当时在公司留下的后遗症&#xff0c;他帮着公司解决&#xff0c;理所当然。 最近有一位程序员…

程序员和领导聚餐晒图,网友回复亮了:发量上就知道谁是新来的

目前大家都知道现在互联网行业的高薪&#xff0c;另外随着互联网行业们&#xff0c;门槛的降低&#xff0c;有很多人都想要加入到和联网行业当中来&#xff0c;而薪资高待遇好也是程序员让人羡慕的一方面&#xff0c;虽然一方面吐槽你互联网行业的辛苦加班&#xff0c;没有个人…

没有五十瓶红牛我是不会告诉你——面试中应该如何正确谈薪

文章末尾给大家留下了大量福利 前言 金九银十已经来临&#xff0c;很多小伙伴已经开始投身跳槽的准备中了。大家选择跳槽无非是想增加自己的工资收入&#xff0c;所以面试过程中的谈薪环节就显得尤为重要&#xff0c;谈的好与不好&#xff0c;未来整个的薪资水平都可能受影响…

为什么明明你做了很多事,到头来领导还是给你打了差评?

阅读本文大概需要 5.33 分钟。 这个问题源于一个队友的疑惑&#xff0c;原问题是 我在国企工作&#xff0c;平时工作之外&#xff0c;多做了很多事情&#xff0c;由于领导不懂技术&#xff0c;年底了&#xff0c;把我当作一般科室人员处理了&#xff0c;感觉看不到未来&#xf…