黃巖路橋網(wǎng)站設(shè)計(jì)google搜索中文入口
在剛剛過(guò)去的 FlutterInProduction 活動(dòng)里,Flutter 官方除了介紹「歷史進(jìn)程」和「用戶(hù)案例」之外,也著重提及了未來(lái)相關(guān)的 roadmap ,其中就有 3.27 里的 Swift Package Manager 、 Widget 實(shí)時(shí)預(yù)覽 和 Dart 與 native 平臺(tái)原生語(yǔ)言直接互操作支持等 case ,但是在最后 Flutter 還提到了一個(gè)有趣的點(diǎn):“Make Flutter Code quicker to write and easier to read” 。
讓 Flutter 代碼變得更好寫(xiě)好讀,這個(gè)點(diǎn)為什么有趣呢?如下圖所示,可以看到 Flutter 提出了一個(gè) Decorators 的支持的例子,也就是讓左邊的代碼可以通過(guò)右邊的組織方式去實(shí)現(xiàn):
這就很有意思了,我們對(duì)比現(xiàn)有 SwiftUI 和 ArkUI 的實(shí)現(xiàn),好家伙,Flutter 這是在準(zhǔn)備把自己 SwiftUI/ArkUI 化嗎?
其實(shí)對(duì)于 SwiftUI 開(kāi)發(fā)者而言,Decorator 模式應(yīng)該并不陌生,因?yàn)?SwiftUI 的設(shè)計(jì)本身就支持 Decorator 模式,開(kāi)發(fā)者應(yīng)用于視圖的每個(gè) modifier 行為都是一個(gè) view wraps, 其實(shí)如果你再對(duì)比 Compose 里的 Modifier ,大家看起來(lái)也是“殊途同歸”:
而回到 Flutter 里,這種代碼被 “SwiftUI/ArkUI 化”的行為體現(xiàn)就在于:
- 原本應(yīng)該是:
Padding(padding: EdgeInsets.all(10), child: MyButton())
- Decorator 之后是:
MyButton().padding(EdgeInsets.all(10))
當(dāng)然,喜歡 Decorator 這種編排方式的人不少,在此之前就有一個(gè)叫 niku 的項(xiàng)目做了類(lèi)似事情,只是它已經(jīng)有一段時(shí)間沒(méi)有更新了,這個(gè)項(xiàng)目通過(guò) typedef
和抽象拓展,利用語(yǔ)法對(duì)官方控件進(jìn)行二次封裝,提前實(shí)現(xiàn)了 Flutter UI 的 Decorator 化:
當(dāng)然,也并不是所有人都喜歡這種 “SwiftUI/ArkUI 化”的行為, 比如 [Flock]https://blog.csdn.net/ZuoYueLiang/article/details/143324672?spm=1001.2014.3001.5501) 的負(fù)責(zé)人就表現(xiàn)的相當(dāng)抗拒:
他在過(guò)去就曾表示過(guò),Flutter widget 樹(shù)一直是聲明性的,開(kāi)發(fā)者是 “聲明” 了樹(shù)的結(jié)構(gòu),而不是 “生成” 了樹(shù),而 Decorator 這種 widget 組合方式,他稱(chēng)之為 builder 模式,他更多覺(jué)得所謂的“干凈”是風(fēng)格偏好,而不是客觀問(wèn)題,“干凈”的感覺(jué)并不能幫助理解問(wèn)題,也不能提供“解決方案”。
Widget build(BuildContext context) {return const Text("Hello, world").padding([Edge.leading, Edge.vertical], 20).padding([Edge.trailing], 8);
}Widget build(BuildContext context) {return Padding(padding: const EdgeInsets.only(right: 8),child: Padding(padding: const EdgeInsets.only(left: 20, top: 20, bottom: 20),child: Text("Hello, world"),),);
}
例如對(duì)于下面代碼的 widget tree ,在每行代碼后面的注釋都有一個(gè)數(shù)字,而這些 tree 里每個(gè) widget 的相對(duì)后代級(jí)別。
Widget build(BuildContext context) {return Scaffold( // 1body: Container( // 2child: const Text("Hello, world") // 5.padding([Edge.leading, Edge.vertical], 20) // 4.padding([Edge.trailing], 8), // 3),),);
}
也就是在一個(gè)普通的聲明式 widget 樹(shù)中,開(kāi)發(fā)者是可以總是從外面向內(nèi)讀取,可以通過(guò)單調(diào)遞增的深度順序閱讀;而在 Decorator 組合下,讀取順序是相反的,實(shí)際 tree 需要從內(nèi)到外閱讀,以一個(gè)單調(diào)遞減的深度順序。
另外他也認(rèn)為,構(gòu)建器會(huì)創(chuàng)建不可預(yù)測(cè)的深度順序,從而損害可讀性并增加混亂,而一旦這種模式流行起來(lái),它們將感染包、包內(nèi)、包內(nèi)的代碼,而隨著這種復(fù)雜性在 package 生態(tài)系統(tǒng)中深入,這種模式的直接復(fù)雜性將乘以數(shù)量級(jí)。
不過(guò)從我的角度上感受,Flutter 如果能完成 “SwiftUI/ArkUI 化”,那么其實(shí)大多數(shù)開(kāi)發(fā)者應(yīng)該還是歡迎的,就像開(kāi)始說(shuō)的,這個(gè)調(diào)整的核心是 “Make Flutter Code quicker to write and easier to read” ,我是覺(jué)得這種模式里,大多場(chǎng)景下開(kāi)發(fā)效率和可觀性還是能提升不少。
當(dāng)然,目前 Decorator 還是評(píng)估階段,還處于「進(jìn)行用戶(hù)研究」的情況,目前官方也擔(dān)心,同時(shí)保持兩個(gè) Widget 模型的復(fù)雜性大于好處。
除此之外,還有其他一些相關(guān)的新特性被提到,例如 Enum shorthands,未來(lái) Flutter 開(kāi)發(fā)者可能只需要做使用 .spaceEvenly
而不是 MainAxisAlignment.spaceEvenly
,這對(duì)于效率提升上來(lái)說(shuō)還是很可觀的:
還有一個(gè)就是 Primary Constructors ,它支持隱式創(chuàng)建變量,從這個(gè)角度看,代碼簡(jiǎn)潔的程度也得到了不少提升,特別如果后續(xù)在宏開(kāi)發(fā)和 JSON 序列化上,整體代碼感受會(huì)更不一樣:
當(dāng)然,可能你就會(huì)覺(jué)得,這又是什么 Kotlin 化的行為~只能說(shuō)是,殊途同歸,殊途同歸~~~
最后,你覺(jué)得 Decorators 這種 “SwiftUI/ArkUI 化” 的實(shí)現(xiàn)是否更符合你的喜好?如果最終落地保持了兩種 Widdget 模式,你會(huì)選擇哪一種呢?
我覺(jué)得倒是不錯(cuò),至少不管是寫(xiě) Flutter、SwiftUI 還是 ArkUI ,“割裂感”會(huì)更低。
參考鏈接
-
https://andrewzuo.com/live-widget-previews-39ed9c86cc80
-
https://www.reddit.com/r/FlutterDev/comments/1hglmas/is_there_a_flutter_decorator_design_documentation/
-
https://blog.flutterbountyhunters.com/the-builder-pattern-is-a-terrible-idea-for-your-widget-tree/
-
https://x.com/SuprDeclarative/status/1869105836779590113