阿里妹導讀:SVG 作為一個強大的矢量圖標準格式,在圖片清晰度的表現力上有著位圖無法比擬的優勢。那么是否 SVG 就是絕對的首選了呢?事實可能并非如此。本文將帶大家了解 SVG 在 Flutter 應用中的性能問題,分享 UC 瀏覽器內核技術團隊在 Flutter 應用中改進 SVG 應用的探索實踐。
文末福利:下載《AliFlutter 體系化建設和實踐》電子書。
例說歷史在計算機的世界里,很多空間優化都隱藏著計算消耗,比如下面這張色彩和形狀豐富的 4k 圖片(其實也可以是 8k,屏幕夠大就可以看到),壓縮后只有 5kB 大小。如果這個 5kB 用 PNG 來存儲的圖片,是下圖這個樣子。表現力天差地別。為了達到類似的清晰度,一般操作系統會協助應用打包時在 UI 資源中歸集多個分辨率的圖片。32x3264x64256x2561024x1024上面這一個圖標,資源包占用超過 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/1831OS 也沒有支持的意向這是可以理解的,因為龐大如 Android 和 iOS 也默認不支持:
大家的共識是,全功能的 SVG 支持工作量不小,還有性能隱患(都是拐著彎提到)。SVG 的鍋,矢量字體方案不用背前面 SVG 咨詢,在建議解決方案中,都提到用矢量字體解決。矢量字體:
雖然在 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_svgflutter_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.resolve stream.setCompleter( _cache.putIfAbsent( key, () => load(key, onError: onError), ), );Debug 和 Profile 模式下,通過添加配合代碼,開發者工具可以在 PictureCache 中查詢所有現存的 SvgPicture 。光柵化時間獲取光柵化的發起接口是 ui.Picutre.toImage 方法,具體的計時在 rasterizer 線程。
補充說明Android VectorDrawableAndroid 提供了一套 VectorDrawable 方案,是一個簡化版的 SVG , 格式和特性不完全兼容,提供轉換工具。從文檔來看,確實是擔心過度復雜的 SVG 影響性能。參考文檔:https://developer.android.com/studio/write/vector-asset-studio單獨 SVG 位圖緩存優化目前 Flutter 用的是一次性光柵化輸出每幀的模式,和 chromium 的 cc 按區域構建位圖再合成不同,如果在光柵化輸出時標記 SVG 的 Picture,緩存這部分位圖可以提升幀數,代價當然是內存損耗。這個功能目前純用 Dart 無法方便實現,因為在 dart.ui 線程中,RenderPicture 無法預見具體的光柵化分辨率。
最后目前,【資源面板】可在阿里內部使用,團隊正在爭取讓 Flutter 主線接受這一改動。歡迎大家探討交流。
? 福利來了??電子書下載《AliFlutter 體系化建設和實踐》
Flutter “快速開發、富有表現力和靈活的 UI、原生性能”的特性和理念讓移動開發者癡狂著迷。阿里如何進行 flutter 體系化建設?有哪些技術沉淀?本書和大家分享閑魚、UC、餓了么等技術團隊在 Flutter 技術及業務應用上的實踐和思考。
關注「阿里技術」把握前沿技術脈搏戳我,下載電子書。
總結
以上是生活随笔為你收集整理的flutter显示图标_如何让 Flutter 应用更好地使用 SVG?的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。