日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

如何让 Flutter 应用更好地使用 SVG?

發(fā)布時(shí)間:2024/9/3 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何让 Flutter 应用更好地使用 SVG? 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
簡(jiǎn)介:SVG 作為一個(gè)強(qiáng)大的矢量圖標(biāo)準(zhǔn)格式,在圖片清晰度的表現(xiàn)力上有著位圖無(wú)法比擬的優(yōu)勢(shì)。那么是否 SVG 就是絕對(duì)的首選了呢?事實(shí)可能并非如此。本文將帶大家了解 SVG 在 Flutter 應(yīng)用中的性能問(wèn)題,分享 UC 瀏覽器內(nèi)核技術(shù)團(tuán)隊(duì)在 Flutter 應(yīng)用中改進(jìn) SVG 應(yīng)用的探索實(shí)踐。

例說(shuō)歷史

在計(jì)算機(jī)的世界里,很多空間優(yōu)化都隱藏著計(jì)算消耗,比如下面這張色彩和形狀豐富的 4k 圖片(其實(shí)也可以是 8k,屏幕夠大就可以看到),壓縮后只有 5kB 大小。

如果這個(gè) 5kB 用 PNG 來(lái)存儲(chǔ)的圖片,是下圖這個(gè)樣子。

表現(xiàn)力天差地別。

為了達(dá)到類(lèi)似的清晰度,一般操作系統(tǒng)會(huì)協(xié)助應(yīng)用打包時(shí)在 UI 資源中歸集多個(gè)分辨率的圖片。


32x32

64x64

256x256

1024x1024

上面這一個(gè)圖標(biāo),資源包占用超過(guò) 120kB,其中最大的一個(gè)版本,運(yùn)行內(nèi)存占用在 4MB。

這么看來(lái),SVG 圖片應(yīng)該是絕對(duì)首選吧?

并非如此。在給 Flutter 做 SVG 支持分析之前,開(kāi)發(fā)者可能覺(jué)得各個(gè)移動(dòng)系統(tǒng) API 中沒(méi)有提供是個(gè)很大缺憾。

而經(jīng)過(guò)光柵化代價(jià)數(shù)據(jù)分析后,也能理解了系統(tǒng)對(duì)盲目使用 SVG 帶來(lái)問(wèn)題的擔(dān)憂(yōu)。

比如還是上面這個(gè) SVG 圖片,在驍龍 626 的手機(jī)上,Flutter 光柵化到 64x64 的區(qū)域需要 34ms,一個(gè) SVG 讓?xiě)?yīng)用與 60 幀流暢度徹底無(wú)緣。實(shí)測(cè) IPhone X 需要 8ms,只能流暢顯示兩個(gè)。

另外補(bǔ)充一點(diǎn),SVG 或者說(shuō)矢量圖的應(yīng)用需求是 UI 扁平化趨勢(shì)興起后才出現(xiàn)的。在擬物化的時(shí)期,拋開(kāi)光柵化速度不說(shuō),矢量圖在顯示寫(xiě)實(shí)風(fēng)格的圖標(biāo)時(shí),缺陷是無(wú)法容忍的。比如 doggy,用最先進(jìn)的追蹤矢量化后(右側(cè)),已經(jīng)數(shù)碼感十足,存儲(chǔ)占用也遠(yuǎn)超 PNG。

好在,扁平化的矢量圖在工程推進(jìn)時(shí),也在有意無(wú)意回避前面說(shuō)的問(wèn)題,大部分都走簡(jiǎn)約風(fēng)。所以只要避開(kāi)陷阱,SVG 還是在很多場(chǎng)景可以做到表現(xiàn)優(yōu)秀的。

應(yīng)用現(xiàn)狀

Flutter 項(xiàng)目主線(xiàn)沒(méi)有支持

Flutter 的基礎(chǔ)組件 Skia 代碼中有 SVG 目錄,但別誤會(huì)了,Skia 只有序列化至 SVG 的功能,沒(méi)有解碼繪制 SVG 的能力。

框架開(kāi)發(fā)計(jì)劃目前也沒(méi)有支持的打算:
https://github.com/flutter/flutter/issues/1831

OS 也沒(méi)有支持的意向

這是可以理解的,因?yàn)辇嫶笕?Android 和 iOS 也默認(rèn)不支持:

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

大家的共識(shí)是,全功能的 SVG 支持工作量不小,還有性能隱患(都是拐著彎提到)。

SVG 的鍋,矢量字體方案不用背

前面 SVG 咨詢(xún),在建議解決方案中,都提到用矢量字體解決。矢量字體:

  • 主流 OS 都自帶的支持。
  • 基本只能單色。
  • 不用依賴(lài) xml。
  • 由于單色輸出,很多圖層繪制疊加等等不可控的性能影響要素都被排除。
  • 系統(tǒng)方便做位圖緩存管理(我們開(kāi)發(fā)者工具后續(xù)可以再研究)。

雖然在 SVG 投入不少研究,也不得不承認(rèn),字體矢量圖輸出是目前很務(wù)實(shí)高效的方案。

配合工具流程改進(jìn) SVG 應(yīng)用

SVG 作為一個(gè)強(qiáng)大的矢量圖標(biāo)準(zhǔn)格式,還是可以找到合適的應(yīng)用的。比如多彩圖標(biāo),方便熱更新,生產(chǎn)工具對(duì)此格式的廣泛支持。

讓 SVG 再次偉大

在 OS 和 runtime 都拋棄 SVG 的情況下,flutter_svg 包毅然然扛起大旗,簡(jiǎn)單快捷的給 Flutter 提供了 SVG 渲染解碼的能力,顯示出 Flutter/Dart 不俗的擴(kuò)展?jié)撃堋?/p>

flutter_svg 的使用非常簡(jiǎn)單,提供和 flutter framework 中 image_provider 類(lèi)似的接口。下面兩段代碼就是分別顯示來(lái)自 asset 和網(wǎng)絡(luò)的 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()), ),

用工具避坑

不能對(duì) SVG 的性能隱患坐視不理。

UC 瀏覽器內(nèi)核技術(shù)團(tuán)隊(duì)開(kāi)發(fā)了一個(gè)【資源面板】工具,可以方便地連接 Flutter 應(yīng)用,實(shí)時(shí)顯示資源分配的內(nèi)存,對(duì)其中的 SVG 圖片,資源面板提供了預(yù)覽和獲取光柵化損耗的功能。

通過(guò)記錄和對(duì)比 SVG 在實(shí)際移動(dòng)設(shè)備上的光柵化損耗,我們可以方便地識(shí)別出有隱患的 SVG 文件,將 SVG 的應(yīng)用安排妥當(dāng)。

通過(guò)實(shí)際 Rasterization Cost 的對(duì)比可以看到,簡(jiǎn)約風(fēng)格的圖標(biāo),時(shí)間消耗到 16.66ms 來(lái)說(shuō)在驍龍 626 上也還是可以接受的。

實(shí)現(xiàn)原理

flutter_svg

flutter_svg 是一個(gè) dart package,提供解析來(lái)自 network、asset、memory 等 SVG 的能力。

由于解析結(jié)果并不是 ui.Image 這樣的位圖,所以 flutter_svg 并沒(méi)有和 ImageCache 協(xié)作,而是自己實(shí)現(xiàn)了一套 PictureCache , PictureCache 中緩存的是 ui.Picture ,這個(gè)類(lèi)實(shí)際是 skia 引擎的 SkPicture Wrapper,二進(jìn)制方式記錄具體的 SVG 繪制指令。

ui.Picture 類(lèi)占用的內(nèi)存不會(huì)很大,緩存基本上是為了避免反復(fù) parse xml。

比如 SvgPicture.asset 的構(gòu)造接口如下:

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 由 來(lái)自 pictureCache 的 completer 填充 ui.Picture 。

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

Debug 和 Profile 模式下,通過(guò)添加配合代碼,開(kāi)發(fā)者工具可以在 PictureCache 中查詢(xún)所有現(xiàn)存的 SvgPicture 。

光柵化時(shí)間獲取

光柵化的發(fā)起接口是 ui.Picutre.toImage 方法,具體的計(jì)時(shí)在 rasterizer 線(xiàn)程。

補(bǔ)充說(shuō)明

Android VectorDrawable

Android 提供了一套 VectorDrawable 方案,是一個(gè)簡(jiǎn)化版的 SVG , 格式和特性不完全兼容,提供轉(zhuǎn)換工具。從文檔來(lái)看,確實(shí)是擔(dān)心過(guò)度復(fù)雜的 SVG 影響性能。參考文檔:
https://developer.android.com/studio/write/vector-asset-studio

單獨(dú) SVG 位圖緩存優(yōu)化

目前 Flutter 用的是一次性光柵化輸出每幀的模式,和 chromium 的 cc 按區(qū)域構(gòu)建位圖再合成不同,如果在光柵化輸出時(shí)標(biāo)記 SVG 的 Picture,緩存這部分位圖可以提升幀數(shù),代價(jià)當(dāng)然是內(nèi)存損耗。

這個(gè)功能目前純用 Dart 無(wú)法方便實(shí)現(xiàn),因?yàn)樵?dart.ui 線(xiàn)程中,RenderPicture 無(wú)法預(yù)見(jiàn)具體的光柵化分辨率。

最后

目前,【資源面板】可在阿里內(nèi)部使用,團(tuán)隊(duì)正在爭(zhēng)取讓 Flutter 主線(xiàn)接受這一改動(dòng)。歡迎大家探討交流。

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

版權(quán)聲明:本文中所有內(nèi)容均屬于阿里云開(kāi)發(fā)者社區(qū)所有,任何媒體、網(wǎng)站或個(gè)人未經(jīng)阿里云開(kāi)發(fā)者社區(qū)協(xié)議授權(quán)不得轉(zhuǎn)載、鏈接、轉(zhuǎn)貼或以其他方式復(fù)制發(fā)布/發(fā)表。申請(qǐng)授權(quán)請(qǐng)郵件developerteam@list.alibaba-inc.com,已獲得阿里云開(kāi)發(fā)者社區(qū)協(xié)議授權(quán)的媒體、網(wǎng)站,在轉(zhuǎn)載使用時(shí)必須注明"稿件來(lái)源:阿里云開(kāi)發(fā)者社區(qū),原文作者姓名",違者本社區(qū)將依法追究責(zé)任。 如果您發(fā)現(xiàn)本社區(qū)中有涉嫌抄襲的內(nèi)容,歡迎發(fā)送郵件至:developer2020@service.aliyun.com 進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),本社區(qū)將立刻刪除涉嫌侵權(quán)內(nèi)容。

總結(jié)

以上是生活随笔為你收集整理的如何让 Flutter 应用更好地使用 SVG?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。