主頁 > 移動端開發 > Flutter 如何將代碼顯示到界面上

Flutter 如何將代碼顯示到界面上

2023-05-05 09:45:57 移動端開發

前言

如何優雅的將專案中的代碼,亦或是你的demo代碼展示到界面上?本文對使用簡單、便于維護且通用的解決方案,進行相關的對比和探究

為了節省大家的時間,把最終解決方案的相關接入和用法寫在前面

預覽代碼

快速開始

  • 接入:pub,github
dependencies:
  code_preview: ^0.1.5
  • 用法:CodePreview,提供需要預覽的className,可自動匹配該類對應的代碼檔案
    • 本來想把寫法簡化成傳入物件,但是因為一些原因無奈放棄,改成了className
    • 具體可以參考下面Flutter Web中的問題模塊的說明
import 'package:code_preview/code_preview.dart';
import 'package:flutter/material.dart';

class Test extends StatelessWidget {
  const Test({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const CodePreview(className: 'Test');
  }
}
  • 使用效果:flutter_smart_dialog

image-20230429215042820

配置代碼檔案

因為原理是遍歷資源檔案,所以必須將需要展示的代碼檔案或者其檔案夾路徑,定義在assets下,這步操作,為大家提供了一個自動化的插件解決

強烈建議需要展示到界面的代碼,都放在統一的檔案夾里管理

  • 展示界面的代碼需要在pugspec.yaml中的assets定義

image-20230422224011359

如果代碼預覽的檔案夾,分級復雜,每次都需要定義路徑實在麻煩

提供一個插件:Flutter Code Helper

  • 安裝:Plugins中搜索Flutter Code Helper

image-20230422225244651

  • pugspec.yaml中定義下需要自動生成檔案夾的路徑,檔案夾隨便套娃,會自動幫你遞回在assets下生成
    • 不需要自動生成,可:不寫該配置,或者配置空陣列(auto_folder: [])
code_helper:
  auto_folder: [ "assets/", "lib/widgets/" ]

Apr-09-2023 22-33-42

說明下:上面的插件是基于RayC的FlutterAssetsGenerator插件專案改的

  • 看了下RayC的插件代碼和相關功能,和我預想的上面功能實作有一定出入,改動起來變動較大
  • 想試下插件專案的各種新配置,直接拉到最新
  • 后期如果想到需要什么功能,方便隨時添加

所以沒向其插件里面提pr,就單獨新開了個插件專案

高級使用

主題

提供倆種代碼樣式主題

  • 日間模式
CodePreview.config = CodePreviewConfig(codeTheme: CodeTheme.light);

image-20230429215716043

  • 夜間模式
CodePreview.config = CodePreviewConfig(codeTheme: CodeTheme.dark);

image-20230429215545723

注釋決議

  • 你可以使用如下的格式,在類上添加注釋
    • key的前面必須加@,舉例(@title,@xxx)
    • key與value的之間,必須使用分號分割,舉例(@xxx: xxx)
    • value如果需要換行,換行的文案前必須加中劃線
/// @title:
///  - test title one
///  - test title two
/// @content: test content
/// @description: test description
class OneWidget extends StatelessWidget {
  const OneWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}
  • 然后可以從customBuilder的回呼獲取param引數,param中擁有parseParam引數
    • 獲取取得上面注釋的資料:param.parseParam['title']或者param.parseParam['***']
    • 獲取的value的型別是List,可兼容多行value的型別
  • customBuilder的用法
    • codeWidget內置的代碼預覽布局,如果你想定義自己預覽代碼的布局,那就可以不使用codeWidget
    • 一般來說,可以根據注釋獲取的資料,結合codeWidget嵌套來自定義符合要求的布局
    • param中含有多個有用內容,可自行查看
import 'package:code_preview/code_preview.dart';
import 'package:flutter/material.dart';

class Test extends StatelessWidget {
  const Test({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return CodePreview(
      className: 'OneWidget',
      customBuilder: (Widget codeWidget, CustomParam? param) {
        debugPrint(param?.parseParam['title'].toString());
        debugPrint(param?.parseParam['content'].toString());
        debugPrint(param?.parseParam['description'].toString());
        return codeWidget;
      },
    );
  }
}
  • 目前內部預覽的布局,會自動去掉類上的注釋,如果想保留注釋,可自行匹配下
 CodePreview.config = CodePreviewConfig(removeParseComment: false);

幾種代碼預覽方案

FlutterUnit方案

  • https://github.com/toly1994328/FlutterUnit

FlutterUnit專案也是自帶代碼預覽方案,這套方案是比較特殊方案

  • 大概看了下,整個FlutterUnit的資料都是基于flutter.db,該檔案里面就有相關demo的文本資訊
  • 所有的demo也是單獨存在一個叫widgets的專案中
  • 所以大概可以猜測出
    • 應該會有個db的輔助工具,會去掃描widgets的專案中的demo代碼
    • 將他們的文本資訊都掃描出來,然后決議上面的注釋等相關資訊,分類存盤到資料庫中,最后生成db檔案

image-20230429172832212

  • 映射表,宿主可以通過db中的組件類名,從這里拿到demo效果實體

image-20230429175714400

總結

整套流程看下來,實作起來的作業量還是有點大的

  • db輔助工具的撰寫
  • 文本注釋相關決議規則
  • 如何便捷的維護db檔案(輔助工具是否支持,生成后自動覆寫宿主db檔案)
  • 不同平臺db檔案的讀取和相關適配

優點

  • 因為掃描工具不依賴Flutter相關庫,預覽方案可以快速的移植到其它編程語言(compose,SwiftUI等)
  • 具備高度自定義,因為是完全獨立的第三方掃描工具,可以隨性所欲的定制化

缺點

  • 最明顯的缺點,應該就是稍微改下demo代碼,就需要三方工具重新生成db檔案(如果三方工具實作的是cli工具,可以將掃描生成命令和push等命令集成一起,應該可以比較好的避免該問題)

build_runner方案

  • https://pub.dev/packages/build_runner

build_runner是個強大代碼自動生成工具,根據ast語法樹+自定義注解資訊,可以生成很多強大的附屬代碼資訊,例如 json_serializable等庫

所以,也能利用這點自定義類注解,獲取到對應的整個類的代碼資訊,在對應附屬的xx.g.dart檔案中,將獲取的代碼內容轉換成字串,然后直接將xx.g.dart檔案的代碼字串資訊,展示到界面就行了

優點

  • 可以通過生成命令,全自動的生成代碼,甚至將整個預覽demo的映射表都可以自動配置完成
  • 可以規范的通過注解配置多個引數

缺點

  • 因為build_runner需要決議整個ast語法樹,一旦專案很大之后,決議生成的時間會非常非常的長!
  • 因為現在很多的這類別庫都是依賴build_runner,所以跑自動生成命令,會導致巨多xx.g.dart檔案被改動,極大的增加cr作業量

資源檔案方案

這應該最常用的一種方案

  • pubspec.yaml中的assets中定義下我們代碼檔案路徑
flutter:
  assets:
    - lib/widgets/show/
  • 然后用loadString獲取檔案內容
final code = await rootBundle.loadString('lib/widgets/show/custome_dialog_animation.dart');

image-20230429205530817

優點

  • 侵入性非常低,不會像build_runnner方案那樣影響到其它模塊
  • 便于維護,如果demo預覽代碼被改變了,打包的時候,資源檔案也會生成對應改變后的代碼檔案

缺點

  • 使用麻煩,使用的時候需要傳入具體的檔案路徑,才能找到想要的代碼資源檔案
  • 需要反復的在pubspec.yaml中的assets里面定義檔案路徑

資源檔案方案優化

上面的三種方案各有優缺點,明確當前的訴求

  • 目前是想寫個簡單的,通用的,僅在Flutter中實作代碼預覽方案

  • 要求使用簡單,高效

  • 維護簡單,多人開發的時候不會有很大成本

FlutterUnit方案:實作起來成本較大,且多人開發對單個db檔案的維護很可能會有點問題,例如:更新代碼的時候,db檔案忘記更新

build_runner方案:生成時間是個問題,還有很對其他型別xx.g.dart檔案產生影響也比較麻煩

資源檔案方案:整體是符合預期的,但是使用時候,需要傳入路徑和pubspec.yaml中反復定義檔案路徑,這是倆個很大痛點

結合實作成本和訴求,選擇資源檔案方案,下面對其痛點進行優化

使用優化

Flutter的編譯產物中,有個相當有用的檔案:AssetManifest.json

AssetManifest.json檔案里面,有所有的資源檔案的路徑,然后就簡單了,我們只需要讀取該檔案內容

final manifestContent = await rootBundle.loadString('AssetManifest.json');

獲取到所有的路徑之后,再結合傳入的類名,讀取所有路徑的檔案內容,然后和傳入的類名做正則匹配就行了

稍微優化

  • 將傳入的類名,轉換為下劃線名稱和所有路徑名稱做匹配,如果能匹配上,再進行內容匹配,匹配成功后就回傳該檔案的代碼內容
  • 如果上述匹配失敗,就進行兜底的全量匹配

優化前

import 'package:code_preview/code_preview.dart';
import 'package:flutter/material.dart';

class Test extends StatelessWidget {
  const Test({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const CodePreview(path: 'lib/widgets/show/custome_dialog_animation.dart');
  }
}

優化后

import 'package:code_preview/code_preview.dart';
import 'package:flutter/material.dart';

class Test extends StatelessWidget {
  const Test({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const CodePreview(className: 'CustomDialogAnimation');
  }
}
  • 一般來說,我是統一配置預覽demo和className,這樣比較好對照

image-20230429170007279

路徑定義優化

本來是想在pubspec.yamlassets里面直接寫通配符定義全路徑,然后悲劇了,它不支持這種寫法

flutter:
  assets:
    - lib/widgets/**/*.dart

GG,只能想其他辦法了,想了很多方法都不行,只能從外部入手,用idea插件的形式,實作自動化掃描生成路徑

  • 安裝:Plugins中搜索Flutter Code Helper

image-20230422225244651

  • pugspec.yaml中定義下需要自動生成檔案夾的目錄,檔案夾隨便套娃,會自動幫你遞回在assets下生成
    • 不需要自動生成,可:不寫該配置,或者配置空陣列(auto_folder: [])
code_helper:
  auto_folder: [ "assets/", "lib/widgets/" ]

Apr-09-2023 22-33-42

Flutter Web中的問題

魔幻的runtimeType

flutter web的release模式中

  • dart2js 會壓縮 JS,這樣會使得型別名被改變
  • 例如:dart中的TestWidgetFunction類的runtimeType,可能會變成minified:Ah,而不是TestWidgetFunction

為啥需要壓縮呢?壓縮名稱可以使得編譯器將 JavaScript體積縮小 3 倍+;精確等效語意和性能/代碼大小之間的權衡,Dart明顯是選擇了后者

這種情況只會在Flutter Web的release模式下發生,其他平臺和Flutter web的Debug | Profile模式都不會有這種問題;所以說Xxx.runtimeType.toString,并不一定會得到預期內的資料,,,

具體討論可參考

  • https://github.com/dart-lang/sdk/issues/35052
  • https://github.com/flutter/flutter/issues/78041

解決思路

  • 將壓縮型別minified:Ah 恢復成 Test
  • 將獲取的Test字串使用相同演算法壓縮成minified:Ah

如有知道如何實作的,務必告訴鄙人

下面從壓縮級別調整的角度,探究是否可解決該問題

dart2js壓縮說明

注:flutter build web默認的是O4優化級別

  • O0: 禁用許多優化,
  • O1: 啟用默認優化(僅是dart2js該命令的默認級別)
  • O2: 在O1優化基礎上,尊重語言語意且對所有程式安全的其他優化(例如縮小)
    • 備注:使用-O2,使用開發JavaScript編譯器編譯時,型別的字串表示不再與Dart VM中的字串表示相同
  • O3: 在O2優化基礎上,并省略隱式型別檢查,
    • 注意:省略型別檢查可能會導致應用程式因型別錯誤而崩潰
  • O4: 在O3優化基礎上,啟用更積極的優化
    • 注意:O4優化容易受到輸入資料變化的影響,在依賴O4之前,需測驗用戶輸入中的邊緣情況

下面是flutter新建專案,未做任何改動,不同壓縮級別的js產物體積

# main.dart.js: 7.379MB
flutter build web --dart2js-optimization O0 
# main.dart.js: 5.073MB
flutter build web --dart2js-optimization O1
# main.dart.js: 1.776MB
flutter build web --dart2js-optimization O2
# main.dart.js: 1.716MB
flutter build web --dart2js-optimization O3
# main.dart.js: 1.687MB
flutter build web --dart2js-optimization O4

總結

  • 預期用法
    • 為什么想使用物件?因為當物件名稱改變時,對應使用的地方,可以便捷觀察到需要改變
    • 可以使用傳入的物件實體,在內部使用runtimeType獲取型別名,再進行相關匹配
CodePreview(code: Test());

但是

綜上可知,使用flutter build web --dart2js-optimization O1編譯的flutter web release產物,能夠使得runtimeType的語意和Dart VM中字串保持一致

但是該壓縮級別下的,js體積過于夸張,務必會對加載速度產生極大影響,可想而知,在復雜專案中的體積增漲肯定更加離譜

對于想要用法更加簡單,使用低級別壓縮命令打包的想法需要舍棄

  • 用法不得已做妥協
CodePreview(className: "Test");

這是個讓我非常糾結的思路歷程

最后

到這里也結束了,自我感覺,對大家應該能有一些幫助

一般來說,大部分團隊,都會有個自己的內部組件庫,因為Flutter強大的跨平臺特性,所以就能很輕松的發布到web平臺,可以方便的體驗各種組件的效果,結合文章中的代碼預覽方案,就可以更加快速的上手各種組件用法了~

好了,下次再見了,靚仔們!

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/551683.html

標籤:其他

上一篇:當我第一次通過Kotlin和Compose來實作一個Canvas時, 我識訓了什么?

下一篇:返回列表

標籤雲
其他(158463) Python(38117) JavaScript(25400) Java(18012) C(15221) 區塊鏈(8261) C#(7972) AI(7469) 爪哇(7425) MySQL(7162) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5871) 数组(5741) R(5409) Linux(5334) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4565) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2432) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1964) Web開發(1951) HtmlCss(1932) python-3.x(1918) 弹簧靴(1913) C++(1912) xml(1889) PostgreSQL(1874) .NETCore(1857) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • Flutter 如何將代碼顯示到界面上

    如何優雅的將專案中的代碼,亦或是你的demo代碼展示到界面上?本文對使用簡單、便于維護且通用的解決方案,進行相關的對比和探究 ......

    uj5u.com 2023-05-05 09:45:57 more
  • 當我第一次通過Kotlin和Compose來實作一個Canvas時, 我識訓了

    自從2019年Google推薦Kotlin為Android開發的首選語言以來已經經歷了將近四年的時間, Compose的1.0版本也發布了將近2年的時間, Kotlin+Compose在現階段的Android開發程序中還遠遠達不到主流的程度. 我們是否應該開始嘗試這個組合? 這個組合有會給我們帶來什... ......

    uj5u.com 2023-04-28 12:21:20 more
  • 當我第一次通過Kotlin和Compose來實作一個Canvas時, 我識訓了

    自從2019年Google推薦Kotlin為Android開發的首選語言以來已經經歷了將近四年的時間, Compose的1.0版本也發布了將近2年的時間, Kotlin+Compose在現階段的Android開發程序中還遠遠達不到主流的程度. 我們是否應該開始嘗試這個組合? 這個組合有會給我們帶來什... ......

    uj5u.com 2023-04-28 12:20:38 more
  • xcode歷史版本下載

    一、背景 較早之前做過一個專案,當時使用swift 3.x開發。 專案結束后就沒再有新需求與更新。 但最近呢需要對專案的某些功能進行調整,專案又重新被拾了起來。 我們知道現在的swift 版本已經到了 5.x, 相應的語法上較 3.x版本也有了不小的變化。使用最新版本的xcode都已經不支持swif ......

    uj5u.com 2023-04-27 11:04:14 more
  • xcode歷史版本下載

    一、背景 較早之前做過一個專案,當時使用swift 3.x開發。 專案結束后就沒再有新需求與更新。 但最近呢需要對專案的某些功能進行調整,專案又重新被拾了起來。 我們知道現在的swift 版本已經到了 5.x, 相應的語法上較 3.x版本也有了不小的變化。使用最新版本的xcode都已經不支持swif ......

    uj5u.com 2023-04-27 10:50:06 more
  • (轉)java.sql.SQLException: An attempt by a client to checkout

    jar包下載方式官網地址:MySQL :: Download Connector/J,如果你打不開官網,在下面我為你準備了直接下載jar包的鏈接地址。 在選擇作業系統時,此處選擇platform independent(獨立于平臺)。 8.0版本的jar包下載地址,點擊直接下載。 https://d ......

    uj5u.com 2023-04-27 09:18:15 more
  • 【FAQ】關于JavaScript版本的華為地圖服務Map的點擊事件與Marker

    一. 問題描述 創建地圖物件,并添加marker標記,對map和marker均添加了點擊事件; <body> <script> function initMap() { // 創建地圖物件 const map = new HWMapJsSDK.HWMap(document.getElementByI ......

    uj5u.com 2023-04-27 09:05:27 more
  • (轉)java.sql.SQLException: An attempt by a client to checkout

    jar包下載方式官網地址:MySQL :: Download Connector/J,如果你打不開官網,在下面我為你準備了直接下載jar包的鏈接地址。 在選擇作業系統時,此處選擇platform independent(獨立于平臺)。 8.0版本的jar包下載地址,點擊直接下載。 https://d ......

    uj5u.com 2023-04-27 08:59:57 more
  • 【FAQ】關于JavaScript版本的華為地圖服務Map的點擊事件與Marker

    一. 問題描述 創建地圖物件,并添加marker標記,對map和marker均添加了點擊事件; <body> <script> function initMap() { // 創建地圖物件 const map = new HWMapJsSDK.HWMap(document.getElementByI ......

    uj5u.com 2023-04-27 08:54:31 more
  • Claude:除ChatGPT外的另一種選擇

    前言 Claude 是 Anthropic 開發的人工智能產品。Anthropic 是由 11 名前 OpenAI 員工于 2022 年創立的人工智能公司,旨在構建安全、可解釋和有益于人類的人工智能系統。Claude 是該公司的第一個產品,得到了谷歌 3 億美元的投資。 與 ChatGPT 有什么區 ......

    uj5u.com 2023-04-26 08:39:35 more