0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

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

OSC開源社區(qū) ? 來源:OSCHINA 社區(qū) ? 2023-05-10 10:04 ? 次閱讀

前言

如何優(yōu)雅的將項(xiàng)目中的代碼,亦或是你的 demo 代碼展示到界面上?本文對(duì)使用簡(jiǎn)單、便于維護(hù)且通用的解決方案,進(jìn)行相關(guān)的對(duì)比和探究

為了節(jié)省大家的時(shí)間,把最終解決方案的相關(guān)接入和用法寫在前面

預(yù)覽代碼

快速開始

接入:pub,github

dependencies:
  code_preview: ^0.1.5

用法:CodePreview,提供需要預(yù)覽的 className,可自動(dòng)匹配該類對(duì)應(yīng)的代碼文件

本來想把寫法簡(jiǎn)化成傳入對(duì)象,但是因?yàn)橐恍┰驘o奈放棄,改成了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

06191504-ee71-11ed-90ce-dac502259ad0.png

配置代碼文件

因?yàn)樵硎潜闅v資源文件,所以必須將需要展示的代碼文件或者其文件夾路徑,定義在 assets 下,這步操作,為大家提供了一個(gè)自動(dòng)化的插件解決

強(qiáng)烈建議需要展示到界面的代碼,都放在統(tǒng)一的文件夾里管理

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

063e2df8-ee71-11ed-90ce-dac502259ad0.png

如果代碼預(yù)覽的文件夾,分級(jí)復(fù)雜,每次都需要定義路徑實(shí)在麻煩

提供一個(gè)插件:Flutter Code Helper

安裝:Plugins 中搜索Flutter Code Helper

066af856-ee71-11ed-90ce-dac502259ad0.png

pugspec.yaml 中定義下需要自動(dòng)生成文件夾的路徑,文件夾隨便套娃,會(huì)自動(dòng)幫你遞歸在 assets 下生成

不需要自動(dòng)生成,可:不寫該配置,或者配置空數(shù)組(auto_folder: [])

code_helper:
  auto_folder: [ "assets/", "lib/widgets/" ]

說明下:上面的插件是基于 RayC 的 FlutterAssetsGenerator 插件項(xiàng)目改的

看了下 RayC 的插件代碼和相關(guān)功能,和我預(yù)想的上面功能實(shí)現(xiàn)有一定出入,改動(dòng)起來變動(dòng)較大

想試下插件項(xiàng)目的各種新配置,直接拉到最新

后期如果想到需要什么功能,方便隨時(shí)添加

所以沒向其插件里面提 pr,就單獨(dú)新開了個(gè)插件項(xiàng)目

高級(jí)使用

主題

提供倆種代碼樣式主題

日間模式

CodePreview.config = CodePreviewConfig(codeTheme: CodeTheme.light);

06816ae6-ee71-11ed-90ce-dac502259ad0.png

夜間模式

CodePreview.config = CodePreviewConfig(codeTheme: CodeTheme.dark);

06a70c42-ee71-11ed-90ce-dac502259ad0.png

注釋解析

你可以使用如下的格式,在類上添加注釋

key 的前面必須加@,舉例(@title,@xxx)

key 與 value 的之間,必須使用分號(hào)分割,舉例(@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的回調(diào)獲取 param 參數(shù),param 中擁有 parseParam 參數(shù)

獲取取得上面注釋的數(shù)據(jù):param.parseParam ['title'] 或者 param.parseParam ['***']

獲取的 value 的類型是 List,可兼容多行 value 的類型

customBuilder的用法

codeWidget內(nèi)置的代碼預(yù)覽布局,如果你想定義自己預(yù)覽代碼的布局,那就可以不使用codeWidget

一般來說,可以根據(jù)注釋獲取的數(shù)據(jù),結(jié)合codeWidget嵌套來自定義符合要求的布局

param中含有多個(gè)有用內(nèi)容,可自行查看

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;
      },
    );
  }
}

目前內(nèi)部預(yù)覽的布局,會(huì)自動(dòng)去掉類上的注釋,如果想保留注釋,可自行匹配下

 CodePreview.config = CodePreviewConfig(removeParseComment: false);

幾種代碼預(yù)覽方案

FlutterUnit 方案

FlutterUnit 項(xiàng)目也是自帶代碼預(yù)覽方案,這套方案是比較特殊方案

大概看了下,整個(gè) FlutterUnit 的數(shù)據(jù)都是基于flutter.db,該文件里面就有相關(guān) demo 的文本信息

所有的 demo 也是單獨(dú)存在一個(gè)叫widgets的項(xiàng)目中

所以大概可以猜測(cè)出

應(yīng)該會(huì)有個(gè) db 的輔助工具,會(huì)去掃描widgets的項(xiàng)目中的 demo 代碼

將他們的文本信息都掃描出來,然后解析上面的注釋等相關(guān)信息,分類存儲(chǔ)到數(shù)據(jù)庫中,最后生成 db 文件

06bf34fc-ee71-11ed-90ce-dac502259ad0.png

映射表,宿主可以通過 db 中的組件類名,從這里拿到 demo 效果實(shí)例

0700048c-ee71-11ed-90ce-dac502259ad0.png

總結(jié)

整套流程看下來,實(shí)現(xiàn)起來的工作量還是有點(diǎn)大的

db 輔助工具的編寫

文本注釋相關(guān)解析規(guī)則

如何便捷的維護(hù) db 文件(輔助工具是否支持,生成后自動(dòng)覆蓋宿主 db 文件)

不同平臺(tái) db 文件的讀取和相關(guān)適配

優(yōu)點(diǎn)

因?yàn)閽呙韫ぞ卟灰蕾?Flutter 相關(guān)庫,預(yù)覽方案可以快速的移植到其它編程語言(compose,SwiftUI 等)

具備高度自定義,因?yàn)槭峭耆?dú)立的第三方掃描工具,可以隨性所欲的定制化

缺點(diǎn)

最明顯的缺點(diǎn),應(yīng)該就是稍微改下 demo 代碼,就需要三方工具重新生成 db 文件(如果三方工具實(shí)現(xiàn)的是 cli 工具,可以將掃描生成命令和 push 等命令集成一起,應(yīng)該可以比較好的避免該問題)

build_runner 方案

build_runner 是個(gè)強(qiáng)大代碼自動(dòng)生成工具,根據(jù) ast 語法樹 + 自定義注解信息,可以生成很多強(qiáng)大的附屬代碼信息,例如json_serializable等庫

所以,也能利用這點(diǎn)自定義類注解,獲取到對(duì)應(yīng)的整個(gè)類的代碼信息,在對(duì)應(yīng)附屬的xx.g.dart文件中,將獲取的代碼內(nèi)容轉(zhuǎn)換成字符串,然后直接將xx.g.dart文件的代碼字符串信息,展示到界面就行了

優(yōu)點(diǎn)

可以通過生成命令,全自動(dòng)的生成代碼,甚至將整個(gè)預(yù)覽 demo 的映射表都可以自動(dòng)配置完成

可以規(guī)范的通過注解配置多個(gè)參數(shù)

缺點(diǎn)

因?yàn)閎uild_runner需要解析整個(gè) ast 語法樹,一旦項(xiàng)目很大之后,解析生成的時(shí)間會(huì)非常非常的長(zhǎng)!

因?yàn)楝F(xiàn)在很多的這類庫都是依賴build_runner,所以跑自動(dòng)生成命令,會(huì)導(dǎo)致巨多xx.g.dart文件被改動(dòng),極大的增加 cr 工作量

資源文件方案

這應(yīng)該最常用的一種方案

在pubspec.yaml中的assets中定義下我們代碼文件路徑

flutter:
  assets:
    - lib/widgets/show/

然后用 loadString 獲取文件內(nèi)容

final code = await rootBundle.loadString('lib/widgets/show/custome_dialog_animation.dart');

072a8b8a-ee71-11ed-90ce-dac502259ad0.png

優(yōu)點(diǎn)

侵入性非常低,不會(huì)像build_runnner方案那樣影響到其它模塊

便于維護(hù),如果 demo 預(yù)覽代碼被改變了,打包的時(shí)候,資源文件也會(huì)生成對(duì)應(yīng)改變后的代碼文件

缺點(diǎn)

使用麻煩,使用的時(shí)候需要傳入具體的文件路徑,才能找到想要的代碼資源文件

需要反復(fù)的在pubspec.yaml中的assets里面定義文件路徑

資源文件方案優(yōu)化

上面的三種方案各有優(yōu)缺點(diǎn),明確當(dāng)前的訴求

目前是想寫個(gè)簡(jiǎn)單的,通用的,僅在 Flutter 中實(shí)現(xiàn)代碼預(yù)覽方案

要求使用簡(jiǎn)單,高效

維護(hù)簡(jiǎn)單,多人開發(fā)的時(shí)候不會(huì)有很大成本

FlutterUnit 方案:實(shí)現(xiàn)起來成本較大,且多人開發(fā)對(duì)單個(gè) db 文件的維護(hù)很可能會(huì)有點(diǎn)問題,例如:更新代碼的時(shí)候,db 文件忘記更新

build_runner 方案:生成時(shí)間是個(gè)問題,還有很對(duì)其他類型xx.g.dart文件產(chǎn)生影響也比較麻煩

資源文件方案:整體是符合預(yù)期的,但是使用時(shí)候,需要傳入路徑和pubspec.yaml中反復(fù)定義文件路徑,這是倆個(gè)很大痛點(diǎn)

結(jié)合實(shí)現(xiàn)成本和訴求,選擇資源文件方案,下面對(duì)其痛點(diǎn)進(jìn)行優(yōu)化

使用優(yōu)化

Flutter 的編譯產(chǎn)物中,有個(gè)相當(dāng)有用的文件:AssetManifest.json

AssetManifest.json 文件里面,有所有的資源文件的路徑,然后就簡(jiǎn)單了,我們只需要讀取該文件內(nèi)容

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

獲取到所有的路徑之后,再結(jié)合傳入的類名,讀取所有路徑的文件內(nèi)容,然后和傳入的類名做正則匹配就行了

稍微優(yōu)化

將傳入的類名,轉(zhuǎn)換為下劃線名稱和所有路徑名稱做匹配,如果能匹配上,再進(jìn)行內(nèi)容匹配,匹配成功后就返回該文件的代碼內(nèi)容

如果上述匹配失敗,就進(jìn)行兜底的全量匹配

優(yōu)化前

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');
  }
}

優(yōu)化后

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');
  }
}

一般來說,我是統(tǒng)一配置預(yù)覽 demo 和 className,這樣比較好對(duì)照

07509834-ee71-11ed-90ce-dac502259ad0.png

路徑定義優(yōu)化

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

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

GG,只能想其他辦法了,想了很多方法都不行,只能從外部入手,用 idea 插件的形式,實(shí)現(xiàn)自動(dòng)化掃描生成路徑

安裝:Plugins 中搜索Flutter Code Helper

066af856-ee71-11ed-90ce-dac502259ad0.png

pugspec.yaml 中定義下需要自動(dòng)生成文件夾的目錄,文件夾隨便套娃,會(huì)自動(dòng)幫你遞歸在 assets 下生成

不需要自動(dòng)生成,可:不寫該配置,或者配置空數(shù)組(auto_folder: [])

code_helper:
  auto_folder: [ "assets/", "lib/widgets/" ]

Flutter Web 中的問題

魔幻的 runtimeType

flutter web 的 release 模式中

dart2js 會(huì)壓縮 JS,這樣會(huì)使得類型名被改變

例如:dart 中的TestWidgetFunction類的 runtimeType,可能會(huì)變成minified:Ah,而不是TestWidgetFunction!

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

這種情況只會(huì)在 Flutter Web 的 release 模式下發(fā)生,其他平臺(tái)和 Flutter web 的 Debug | Profile 模式都不會(huì)有這種問題;所以說Xxx.runtimeType.toString,并不一定會(huì)得到預(yù)期內(nèi)的數(shù)據(jù)。。。

解決思路

將壓縮類型minified:Ah恢復(fù)成Test

將獲取的Test字符串使用相同算法壓縮成minified:Ah

如有知道如何實(shí)現(xiàn)的,務(wù)必告訴鄙人

下面從壓縮級(jí)別調(diào)整的角度,探究是否可解決該問題

dart2js 壓縮說明

注:flutter build web 默認(rèn)的是 O4 優(yōu)化級(jí)別

O0: 禁用許多優(yōu)化。

O1: 啟用默認(rèn)優(yōu)化 (僅是 dart2js 該命令的默認(rèn)級(jí)別)

O2: 在 O1 優(yōu)化基礎(chǔ)上,尊重語言語義且對(duì)所有程序安全的其他優(yōu)化(例如縮?。?/p>

備注:使用 - O2, 使用開發(fā) JavaScript 編譯器編譯時(shí),類型的字符串表示不再與 Dart VM 中的字符串表示相同

O3: 在 O2 優(yōu)化基礎(chǔ)上,并省略隱式類型檢查。

注意:省略類型檢查可能會(huì)導(dǎo)致應(yīng)用程序因類型錯(cuò)誤而崩潰

O4: 在 O3 優(yōu)化基礎(chǔ)上,啟用更積極的優(yōu)化

注意:O4 優(yōu)化容易受到輸入數(shù)據(jù)變化的影響,在依賴 O4 之前,需測(cè)試用戶輸入中的邊緣情況

下面是 flutter 新建項(xiàng)目,未做任何改動(dòng),不同壓縮級(jí)別的 js 產(chǎn)物體積

# 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

總結(jié)

預(yù)期用法

為什么想使用對(duì)象?因?yàn)楫?dāng)對(duì)象名稱改變時(shí),對(duì)應(yīng)使用的地方,可以便捷觀察到需要改變

可以使用傳入的對(duì)象實(shí)例,在內(nèi)部使用 runtimeType 獲取類型名,再進(jìn)行相關(guān)匹配

CodePreview(code: Test());

但是

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

但是該壓縮級(jí)別下的,js 體積過于夸張,務(wù)必會(huì)對(duì)加載速度產(chǎn)生極大影響,可想而知,在復(fù)雜項(xiàng)目中的體積增漲肯定更加離譜

對(duì)于想要用法更加簡(jiǎn)單,使用低級(jí)別壓縮命令打包的想法需要舍棄

用法不得已做妥協(xié)

CodePreview(className: "Test");

這是個(gè)讓我非常糾結(jié)的思路歷程

最后

到這里也結(jié)束了,自我感覺,對(duì)大家應(yīng)該能有一些幫助

一般來說,大部分團(tuán)隊(duì),都會(huì)有個(gè)自己的內(nèi)部組件庫,因?yàn)?Flutter 強(qiáng)大的跨平臺(tái)特性,所以就能很輕松的發(fā)布到 web 平臺(tái),可以方便的體驗(yàn)各種組件的效果,結(jié)合文章中的代碼預(yù)覽方案,就可以更加快速的上手各種組件用法了~





審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Rayc
    +關(guān)注

    關(guān)注

    0

    文章

    2

    瀏覽量

    6012
  • flutter
    +關(guān)注

    關(guān)注

    0

    文章

    13

    瀏覽量

    432

原文標(biāo)題:Flutter如何將代碼顯示到界面上

文章出處:【微信號(hào):OSC開源社區(qū),微信公眾號(hào):OSC開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    鴻蒙Flutter實(shí)戰(zhàn):07混合開發(fā)

    # 鴻蒙Flutter實(shí)戰(zhàn):混合開發(fā) 鴻蒙Flutter混合開發(fā)主要有兩種形式。 ## 1.基于har flutter module打包成har包,在原生鴻蒙項(xiàng)目中,以har包
    發(fā)表于 10-23 16:00

    鴻蒙Flutter實(shí)戰(zhàn):08-如何調(diào)試代碼

    ,找到 Flutter Attach , Flutter 調(diào)試器連接至宿主機(jī) 然后就是增加斷點(diǎn),使用hot reload 重新加載 Flutter,調(diào)試項(xiàng)目
    發(fā)表于 10-23 16:29

    鴻蒙Flutter實(shí)戰(zhàn):11-使用 Flutter SDK 3.22.0

    # 使用 Flutter SDK 3.22.0 ## SDK 安裝 參考[鴻蒙Flutter實(shí)戰(zhàn):01-搭建開發(fā)環(huán)境]文章的說明,首先安裝 Flutter SDK 3.22.0。 目前鴻蒙化
    發(fā)表于 11-01 15:03

    深入理解flutter的編譯原理與優(yōu)化

    摘要: 閑魚技術(shù)-正物 問題背景 對(duì)于開發(fā)者而言,什么是Flutter?它是用什么語言編寫的,包含哪幾部分,是如何被編譯,運(yùn)行設(shè)備上的?Flutter如何做到Debug模式Hot
    發(fā)表于 07-02 17:47

    如何將代碼集成Multi IDE Project?

    我想知道是否可以使用PinMap向?qū)蒀代碼以與Multi IDE Green Hill編譯器一起使用,如果可以的話,如何將代碼集成Multi IDE Project? 提前致
    發(fā)表于 06-21 10:05

    界面上顯示和輸入控件特別多時(shí)如何管理

    如果在一個(gè)界面上有幾十個(gè)控件(顯示和輸入都有),類型還不一樣,請(qǐng)問如何管理這些控件,現(xiàn)在我都是用很多事件結(jié)構(gòu)來做的,請(qǐng)問大家有什么好的方法?特別是在ActorFramework框架中。
    發(fā)表于 09-09 19:32

    如何將現(xiàn)有代碼一點(diǎn)點(diǎn)移植HC32F460上

    如何將現(xiàn)有代碼一點(diǎn)點(diǎn)移植HC32F460上?其移植過程是怎樣的?
    發(fā)表于 11-25 06:27

    如何將STM32的代碼以日期作為軟件版本號(hào)去實(shí)現(xiàn)

    如何將STM32的代碼以日期作為軟件版本號(hào)去實(shí)現(xiàn)?求大神解答
    發(fā)表于 12-15 06:20

    如何將顯示緩沖區(qū)的數(shù)據(jù)取出拼裝成一個(gè)字節(jié)

    如何將顯示緩沖區(qū)的數(shù)據(jù)取出拼裝成一個(gè)字節(jié)?如何修改程序?
    發(fā)表于 01-21 07:34

    如何將示例flutter應(yīng)用程序安裝到STM32MP157F-DK2?

    /environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabiexport CC=${CLANGCC}export CXX=${CLANGCXX}我的問題是如何將一個(gè)簡(jiǎn)單的 flutter 應(yīng)用程序安裝到我的發(fā)現(xiàn)
    發(fā)表于 12-06 07:14

    如何將ST25dv sdk移植Flutter?

    我想開發(fā)一個(gè)簡(jiǎn)單的應(yīng)用程序來讀/寫 ST25DV 設(shè)備的內(nèi)部 EEPROM。是否有 ST25dv sdk Flutter 的移植?
    發(fā)表于 01-03 09:01

    如何將BLDC進(jìn)電機(jī)控制算法移植STM微控制器上?

    為 STSPIN 提供的 6 步算法。我們應(yīng)該將該代碼移植到任何其他 ST 控制器嗎?如何將BLDC進(jìn)電機(jī)控制算法移植STM微控制器上?
    發(fā)表于 01-17 08:54

    如何將X-CUBE-NFC5代碼集成平臺(tái)中?

    ,我只是主要的 .c 和 .h 文件從 RFAL 和 BSP 文件夾復(fù)制項(xiàng)目中,但出現(xiàn)了很多錯(cuò)誤。是否有關(guān)于如何將代碼添加到項(xiàng)目或我需要使用哪些軟件來使用 X-CUBE-NFC5
    發(fā)表于 02-02 07:22

    如何將JavaScript代碼嵌入HTML頁面

    本教程向您展示如何將JavaScript代碼嵌入HTML頁面,來幫助您開始學(xué)習(xí) JavaScript。
    的頭像 發(fā)表于 12-14 17:46 ?1131次閱讀

    Flutter 共創(chuàng)未來 | Flutter Forward 活動(dòng)精彩回顧

    。 Flutter Forward 活動(dòng) https://flutter.dev/events/flutter-forward Flutter 是一個(gè)
    的頭像 發(fā)表于 02-22 23:20 ?555次閱讀