简介:SVG 作为一个强大的矢量图标准格式,在图片清晰度的表现力上有着位图无法比拟的优势。那么是否 SVG 就是绝对的首选了呢?事实可能并非如此。本文将带大家了解 SVG 在 Flutter 应用中的性能问题,分享 UC 浏览器内核技术团队在 Flutter 应用中改进 SVG 应用的探索实践。

例说历史

在计算机的世界里,很多空间优化都隐藏着计算消耗,比如下面这张色彩和形状丰富的 4k 图片(其实也可以是 8k,屏幕够大就可以看到),压缩后只有 5kB 大小。

如果这个 5kB 用 PNG 来存储的图片,是下图这个样子。

表现力天差地别。

为了达到类似的清晰度,一般操作系统会协助应用打包时在 UI 资源中归集多个分辨率的图片。


32x32

64x64

256x256

1024x1024

上面这一个图标,资源包占用超过 120kB,其中最大的一个版本,运行内存占用在 4MB。

这么看来,SVG 图片应该是绝对首选吧?

并非如此。在给 Flutter 做 SVG 支持分析之前,开发者可能觉得各个移动系统 API 中没有提供是个很大缺憾。

而经过光栅化代价数据分析后,也能理解了系统对盲目使用 SVG 带来问题的担忧。

比如还是上面这个 SVG 图片,在骁龙 626 的手机上,Flutter 光栅化到 64x64 的区域需要 34ms,一个 SVG 让应用与 60 帧流畅度彻底无缘。实测 IPhone X 需要 8ms,只能流畅显示两个。

另外补充一点,SVG 或者说矢量图的应用需求是 UI 扁平化趋势兴起后才出现的。在拟物化的时期,抛开光栅化速度不说,矢量图在显示写实风格的图标时,缺陷是无法容忍的。比如 doggy,用最先进的追踪矢量化后(右侧),已经数码感十足,存储占用也远超 PNG。

好在,扁平化的矢量图在工程推进时,也在有意无意回避前面说的问题,大部分都走简约风。所以只要避开陷阱,SVG 还是在很多场景可以做到表现优秀的。

应用现状

Flutter 项目主线没有支持

Flutter 的基础组件 Skia 代码中有 SVG 目录,但别误会了,Skia 只有序列化至 SVG 的功能,没有解码绘制 SVG 的能力。

框架开发计划目前也没有支持的打算:
https://github.com/flutter/flutter/issues/1831

OS 也没有支持的意向

这是可以理解的,因为庞大如 Android 和 iOS 也默认不支持:

  • https://stackoverflow.com/questions/34990236/how-to-use-svg-image-in-imageview
  • https://stackoverflow.com/questions/35691839/how-to-display-svg-image-using-swift

大家的共识是,全功能的 SVG 支持工作量不小,还有性能隐患(都是拐着弯提到)。

SVG 的锅,矢量字体方案不用背

前面 SVG 咨询,在建议解决方案中,都提到用矢量字体解决。矢量字体:

  • 主流 OS 都自带的支持。
  • 基本只能单色。
  • 不用依赖 xml。
  • 由于单色输出,很多图层绘制叠加等等不可控的性能影响要素都被排除。
  • 系统方便做位图缓存管理(我们开发者工具后续可以再研究)。

虽然在 SVG 投入不少研究,也不得不承认,字体矢量图输出是目前很务实高效的方案。

配合工具流程改进 SVG 应用

SVG 作为一个强大的矢量图标准格式,还是可以找到合适的应用的。比如多彩图标,方便热更新,生产工具对此格式的广泛支持。

让 SVG 再次伟大

在 OS 和 runtime 都抛弃 SVG 的情况下,flutter_svg 包毅然然扛起大旗,简单快捷的给 Flutter 提供了 SVG 渲染解码的能力,显示出 Flutter/Dart 不俗的扩展潜能。

flutter_svg 的使用非常简单,提供和 flutter framework 中 image_provider 类似的接口。下面两段代码就是分别显示来自 asset 和网络的 SVG 图片:

SvgPicture.asset('assets/adsmall.svg',placeholderBuilder: (BuildContext context) => Container(child: const CircularProgressIndicator()),
),SvgPicture.network('https://raw.githubusercontent.com/dnfield/flutter_svg/master/example/assets/deborah_ufw/new-camera.svg',placeholderBuilder: (BuildContext context) => Container(child: const CircularProgressIndicator()),
),

用工具避坑

不能对 SVG 的性能隐患坐视不理。

UC 浏览器内核技术团队开发了一个【资源面板】工具,可以方便地连接 Flutter 应用,实时显示资源分配的内存,对其中的 SVG 图片,资源面板提供了预览和获取光栅化损耗的功能。

通过记录和对比 SVG 在实际移动设备上的光栅化损耗,我们可以方便地识别出有隐患的 SVG 文件,将 SVG 的应用安排妥当。

通过实际 Rasterization Cost 的对比可以看到,简约风格的图标,时间消耗到 16.66ms 来说在骁龙 626 上也还是可以接受的。

实现原理

flutter_svg

flutter_svg 是一个 dart package,提供解析来自 network、asset、memory 等 SVG 的能力。

由于解析结果并不是 ui.Image 这样的位图,所以 flutter_svg 并没有和 ImageCache 协作,而是自己实现了一套 PictureCache , PictureCache 中缓存的是 ui.Picture ,这个类实际是 skia 引擎的 SkPicture Wrapper,二进制方式记录具体的 SVG 绘制指令。

ui.Picture 类占用的内存不会很大,缓存基本上是为了避免反复 parse xml。

比如 SvgPicture.asset 的构造接口如下:

SvgPicture.asset(String assetName, {Key key,this.matchTextDirection = false,AssetBundle bundle,String package,this.width,this.height,this.fit = BoxFit.contain,this.alignment = Alignment.center,this.allowDrawingOutsideViewBox = false,this.placeholderBuilder,Color color,BlendMode colorBlendMode = BlendMode.srcIn,this.semanticsLabel,this.excludeFromSemantics = false,})  : pictureProvider = ExactAssetPicture(allowDrawingOutsideViewBox == true? svgStringDecoderOutsideViewBox: svgStringDecoder,assetName,bundle: bundle,package: package,colorFilter: _getColorFilter(color, colorBlendMode)),super(key: key);

SvgPicture 的 _picture,由 pictureProvider 的 stream 通知更新:

void _resolveImage() {final PictureStream newStream = widget.pictureProvider.resolve(createLocalPictureConfiguration(context));assert(newStream != null);_updateSourceStream(newStream);}

pictureProvider 的 stream 由 来自 pictureCache 的 completer 填充 ui.Picture 。

// in PictureProvider<T>.resolvestream.setCompleter(_cache.putIfAbsent(key,() => load(key, onError: onError),),);

Debug 和 Profile 模式下,通过添加配合代码,开发者工具可以在 PictureCache 中查询所有现存的 SvgPicture 。

光栅化时间获取

光栅化的发起接口是 ui.Picutre.toImage 方法,具体的计时在 rasterizer 线程。

补充说明

Android VectorDrawable

Android 提供了一套 VectorDrawable 方案,是一个简化版的 SVG , 格式和特性不完全兼容,提供转换工具。从文档来看,确实是担心过度复杂的 SVG 影响性能。参考文档:
https://developer.android.com/studio/write/vector-asset-studio

单独 SVG 位图缓存优化

目前 Flutter 用的是一次性光栅化输出每帧的模式,和 chromium 的 cc 按区域构建位图再合成不同,如果在光栅化输出时标记 SVG 的 Picture,缓存这部分位图可以提升帧数,代价当然是内存损耗。

这个功能目前纯用 Dart 无法方便实现,因为在 dart.ui 线程中,RenderPicture 无法预见具体的光栅化分辨率。

最后

目前,【资源面板】可在阿里内部使用,团队正在争取让 Flutter 主线接受这一改动。欢迎大家探讨交流。

原文链接:https://developer.aliyun.com/article/767038?

版权声明:本文中所有内容均属于阿里云开发者社区所有,任何媒体、网站或个人未经阿里云开发者社区协议授权不得转载、链接、转贴或以其他方式复制发布/发表。申请授权请邮件developerteam@list.alibaba-inc.com,已获得阿里云开发者社区协议授权的媒体、网站,在转载使用时必须注明"稿件来源:阿里云开发者社区,原文作者姓名",违者本社区将依法追究责任。 如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:developer2020@service.aliyun.com 进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。

如何让 Flutter 应用更好地使用 SVG?相关推荐

  1. flutter显示图标_如何让 Flutter 应用更好地使用 SVG?

    阿里妹导读:SVG 作为一个强大的矢量图标准格式,在图片清晰度的表现力上有着位图无法比拟的优势.那么是否 SVG 就是绝对的首选了呢?事实可能并非如此.本文将带大家了解 SVG 在 Flutter 应 ...

  2. 50兆 svg 文件超过_如何让 Flutter 应用更好地使用 SVG?

    简介:SVG 作为一个强大的矢量图标准格式,在图片清晰度的表现力上有着位图无法比拟的优势.那么是否 SVG 就是绝对的首选了呢?事实可能并非如此.本文将带大家了解 SVG 在 Flutter 应用中的 ...

  3. 获取不到svg中的对象_阿里技术:如何让 Flutter 应用更好地使用 SVG?

    作者:领蜂 阿里技术 阿里妹导读:SVG 作为一个强大的矢量图标准格式,在图片清晰度的表现力上有着位图无法比拟的优势.那么是否 SVG 就是绝对的首选了呢?事实可能并非如此.本文将带大家了解 SVG ...

  4. 在Flutter中更快地加载您的图像资源

    本文主要介绍在Flutter中更快地加载您的图像资源 我们可以将图像放在我们的资产文件夹中,但如何更快地加载它们?这是 Flutter 中的一个秘密函数,可以帮助我们做到这一点 - precacheI ...

  5. .chm文件与.doc文件互相转换(一).chm转.doc

    简介 本文将描述如何将一个.chm文档转化为一个.doc文档. 准备工具:下载一个CHM2Word 2012软件即可. 本文CHM2Word 2012的未破解,试用30天,网上应该有破解版. 安装 转 ...

  6. Flutter开发之认识Flutter(二)

    在第一篇大概了解到Flutter是干什么的,属于跨平台开发,跟之前的RN 属于同一类.下面继续了解Flutter的起源.Flutter和其他平台的对比.Flutter开发语言Dart. 1.Flutt ...

  7. android应用程序开发_Kotlin与Flutter:Android跨平台应用程序开发,到底选择哪个?...

    移动互联时代--应用为王 移动互联网时代,很难想象没有应用程序的生活.从我们睁眼醒来的那一刻到我们真正睡觉的那一刻,无数的应用程序围绕着我们.根据统计,国人平均在移动设备上花费4个小时以上! 而这其中 ...

  8. Flutter Live 2018 Flutter 1.0 发布

    原文链接 Flutter Live 2018 在 12 月 4 日 晚上进行全球同步直播,知识小集团队一直关注着 Flutter 的发展,并在公众号中多次推送 Flutter 相关的文章.如果你对 F ...

  9. flutter和webapp_Flutter Web Beta版本终于发布了

    在昨天的Flutter Interact大会中,谷歌Flutter团队给我们带来了最新的Flutter 1.12版本,在此次版本更新中,其中一个吸引人的功能就是"Flutter Web Be ...

最新文章

  1. 编程之美:无差错二分查找
  2. Windows Server 2008 R2 SP1遗忘管理员密码后的解决方案
  3. php获取当前时间的毫秒数,并且利用它测试代码段执行时间
  4. HDU 5816 Hearthstone
  5. 算法提高课-图论-欧拉回路和欧拉路径-AcWing 1124. 骑马修栅栏:欧拉路径、dfs
  6. 电脑不能访问服务器指定端口6,windows server2008 无法访问本机及其他服务器的所有端口...
  7. python 减少可调用对象的参数个数
  8. python中说_name_没有被定义_python – 为什么我得到这个NameError:名称’url_for’没有定义?...
  9. 凸优化-Proximal GD
  10. c语言设计题库及详解答案,c语言程序设计题库及其答案
  11. 如何快速学习一门技术?十步学习法
  12. 如何查看Mac系统的位数
  13. Java8 Lambda表达式的特快处理流Stream快速入门
  14. vander范德蒙德行列式
  15. JAVA——从基础学起(五)类和对象
  16. linux下c语言按q退出_linux下C语言多线程(四)线程中止
  17. CAE(Convolutional Auto-Encode) 卷积自编码
  18. VS 2022 中英文切换
  19. html网页制作之细谈HTML前端项目开发过程中的细节及心得_避免入坑
  20. 使用99编程 —— EDA拼接屏大规模图像处理

热门文章

  1. 阿里员工发帖吐槽人不如驴:你不能一边抽我,一边问我爱不爱你
  2. html中属性选择器是什么,为什么在CSS选择器/ HTML属性中首选使用破折号?
  3. java中获取错误,在简单程序中获取分段错误
  4. mac远程桌面连接windows_web浏览器通过Myrtille连接Windows远程桌面
  5. mysql知识结构图_MySql知识结构说明
  6. 通过doi可以检索到文献_怎么查看中外文献的期号和卷号?
  7. python线程间通信_python多线程之事件触发(线程间通信)
  8. 一个用python做的完整项目_我从一个小项目学习Python编程的全过程(二)
  9. 高起专计算机应用基础试题及答案,重庆大学网络教育高起专计算机应用基础入学考试模拟题及答案(二)...
  10. The Preliminary Contest for ICPC Asia Nanjing 2019ICPC南京网络赛