原創(chuàng):有趣知識點摸索型文章
創(chuàng)作不易豺憔,請珍惜额获,之后會持續(xù)更新够庙,不斷完善
個人比較喜歡做筆記和寫總結,畢竟好記性不如爛筆頭哈哈抄邀,這些文章記錄了我的IOS成長歷程耘眨,希望能與大家一起進步
溫馨提示:由于簡書不支持目錄跳轉,大家可通過command + F 輸入目錄標題后迅速尋找到你所需要的內容
目錄
- 一境肾、ReactNative
- 二剔难、Weex
- 三、為什么選擇用Flutter
- 四准夷、Flutter開發(fā)語言Dart
一钥飞、ReactNative
從零入門ReactNative的建議
- 需要有
html
莺掠、js
衫嵌、css
等前端編程語言 - 然后,先去理解
React
基本使用 - 搭建
ReactNative
開發(fā)環(huán)境彻秆,選用iOS/Android
先把項目運行起來楔绞。 - 學習
ReactNative
基本開發(fā)流程。 - 寫頁面必須先搞懂
flex
布局方式唇兑。 - 學習
ReactNative
相關組件酒朵。 - 深入學習
ReactNative
的原理等高級知識。 - 閱讀源碼扎附,真正的搞懂它蔫耽。
1、相關命令
搭建環(huán)境
依賴 Node
環(huán)境
brew install node
node -v 查看node版本
sudo npm cache clean -f 清除緩存
sudo n stable 升級到穩(wěn)定版本
sudo npm install -g n 按照node
安裝 watchman
留夜。其是 facebook
的一個開源項目匙铡,它開源用來監(jiān)視文件并且記錄文件的改動情況,當文件變更它可以觸發(fā)一些操作碍粥,例如執(zhí)行一些命令等等鳖眼。
brew install watchman
創(chuàng)建項目
npx react-native init xxx_name_xxx
通過代碼啟動工程或者直接使用 Xcode 啟動工程編譯調試
yarn iOS
react-native
相關命令
react-native init MyAppName --version 0.64.0
react-native --version 查看版本
npx react-native info 命令查看當前的版本
2、工程目錄
- 工程入口代碼文件
index.js
嚼摩,類似 iOS 中的main.m
文件钦讳。 - App組件定義
App.js
,當然也可以新建文件定義組件枕面,類似 iOS 中的AppDelegate.m
文件愿卒。 - iOS 和 Android 兩個文件夾是原生相關的工程。
-
package.json
工程的配置文件潮秘,定義腳本命令琼开、包依賴、測試等相關 - 相關依賴庫
node_modules
-
App.json
RN
模塊的配置唇跨。其中name
配置字符串稠通,必須和RCTRootView
初始化initWithBridge:moduleName:initialProperties:
用到的moduleName
一樣衬衬。
{ "name": "HelloFirstRNDemo",
"displayName": "HelloFirstRNDemo"}
3、開發(fā)基本流程
ReactNative 代碼
1改橘、在App.js
中滋尉,導入 RN
相關的組件,其中包括系統(tǒng)組件與自定義組件的導入
import React from 'react';
import {
SafeAreaView,
ScrollView,
StatusBar,
Text,
useColorScheme,
View,
} from 'react-native';
2飞主、在App.js
中狮惜,自定義組件,即搭建頁面碌识。
class HelloWorld extends React.Component {
render() {
return (
<SafeAreaView>
<Text style={styles.title}> hello my world! </Text>
<ScrollView>
<Section> section 1</Section>
</SafeAreaView>
)
}
}
3碾篡、在App.js
中,定義樣式筏餐,推薦統(tǒng)一定義樣式开泽,RN
使用布局方式為Flex
布局。
const styles = StyleSheet.create({
title: {
fontSize: 42,
},
});
4魁瞪、在index.js
中穆律,組件的注冊。
import {AppRegistry} from 'react-native';
import {HelloWorld} from './App';
import {name as appName} from './app.json';
// 第一個參數(shù):應用名稱导俘,第二個參數(shù):組件名峦耘。
AppRegistry.registerComponent(appName, () => HelloWorld);
原生端(iOS為例)
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
// 其中 self 為實現(xiàn) RCTBridgeDelegate 的實例,必須實現(xiàn)方法如下:
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
NSURL *url = nil;
#if DEBUG
url = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
url = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
return url;
}
初始化ReactNative
代碼的加載容器類RCTRootView
旅薄。
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:@"FirstRNDemo"
initialProperties:nil];
二辅髓、Weex
1、概述
阿里巴巴在Qcon大會上宣布跨平臺移動開發(fā)工具 Weex
開放內測邀請少梁。Weex
能夠完美兼顧性能與動態(tài)性洛口,讓移動開發(fā)者通過簡捷的前端語法寫出 Native
級別的性能體驗,并支持 iOS猎莲、安卓绍弟、YunOS 及 Web 等多端部署。
近一年來著洼,ReactNative
和 Weex
這些跨平臺技術對 Native
開發(fā)者來說樟遣,沖擊是巨大的。Native
在開發(fā)App的時候存在一些弊端身笤,比如客戶端需要頻繁更新豹悬,iOS更新時間還要受到審核的牽制;iOS液荸、Android 和前端同時開發(fā)同一個需求瞻佛,在人員成本上消耗大;Hybrid
的性能和 Native
相比又差了一點。ReactNative
和 Weex
的出現(xiàn)伤柄,就是為了解決這些痛點的绊困。
Weex
從出生那天起,仿佛就是和 ReactNative
是一對适刀。ReactNative
宣稱 “Learn once, write anywhere”秤朗,而 Weex
宣稱“Write Once, Run Everywhere”。Weex
從出生那天起笔喉,就被給予了一統(tǒng)三端的厚望取视。ReactNative
可以支持 iOS、Android常挚,而 Weex
可以支持iOS作谭、Android、HTML5奄毡。一統(tǒng)三端就解決了前言里面說的第二個痛點折欠,同時開發(fā)浪費人員成本的問題。
Native
移動開發(fā)者只需要在本地導入 Weex
的 SDK秧倾,就可以通過 HTML/CSS/JavaScript
網(wǎng)頁的這套編程語言來開發(fā) Native
級別的 Weex
界面怨酝。這意味著可以直接用現(xiàn)有 Web
開發(fā)的編輯器和 IDE
的代碼補全傀缩、提示那先、檢查等功能。從而也給前端人員開發(fā) Native
端赡艰,較低的開發(fā)成本和學習成本售淡。
Weex
是一種輕量級、可擴展慷垮、高性能框架揖闸。集成也很方便,可以直接在 HTML5
頁面嵌入料身,也可嵌在原生UI中汤纸。由于和 ReactNative
一樣,都會調用 Native
端的原生控件芹血,所以在性能上比 Hybrid
高出一個層次贮泞。這就解決了前言里面所說的第三個痛點,性能問題幔烛。
Weex
非常輕量啃擦,體積小巧,語法簡單饿悬,方便接入和上手令蛉。ReactNative
官方只允許將 ReactNative
基礎js
庫和業(yè)務JS
一起打成一個 JS bundle
,沒有提供分包的功能狡恬,所以如果想節(jié)約流量就必須制作分包打包工具珠叔。而 Weex
默認打的 JS bundle
只包含業(yè)務 JS
代碼蝎宇,體積小很多,基礎 JS
庫包含在 Weex SDK
中祷安,這一點 Weex
與 Facebook 的 React Native
相比夫啊,Weex
更加輕量,體積小巧辆憔。把 Weex
生成的 JS bundle
輕松部署到服務器端撇眯,然后 Push
到客戶端,或者客戶端請求新的資源即可完成發(fā)布虱咧。如此快速的迭代就解決了前言里面說的第一個痛點熊榛,發(fā)布無法控制時間。
Weex
中 Native
組件和 API 都可以橫向擴展腕巡,業(yè)務方可去中心化橫向靈活化定制組件和功能模塊玄坦。并且還可以直接復用 Web
前端的工程化管理和監(jiān)控性能等工具。
2绘沉、工作原理
上圖是官方給的一張原理圖煎楣,Weex
是如何把JS打包成JS Bundle
的原理本篇文章暫時不涉及。本篇文章會詳細分析Weex
是如何在Native
端工作的车伞。筆者把Native
端的原理再次細分择懂,如下圖:
Weex
可以通過自己設計的DSL
,書寫.we
文件或者.vue
文件來開發(fā)界面另玖,整個頁面書寫分成了3段困曙,template
、style
谦去、script
慷丽,借鑒了成熟的 MVVM
的思想。
Weex
在性能方面鳄哭,為了盡可能的提升客戶端的性能要糊,DSL
的Transformer
全部都放在了服務器端實現(xiàn),Weex
會在服務器端將XML + CSS + JavaScript
代碼全部都轉換成JS Bundle
妆丘。服務器將JS Bundle
部署到Server
上和CDN
上锄俄。
Weex
和React Native
不同的是,Weex
把JS Framework
內置在SDK
里面飘痛,用來解析從服務器上下載的JS Bundle
珊膜,這樣也減少了每個JS Bundle
的體積,不再有React Native
需要分包的問題宣脉〕的客戶端請求完JS Bundle
以后,傳給JS Framework
,JS Framework
解析完成以后會輸出Json
格式的Virtual DOM
竹祷,客戶端Native
只需要專心負責 Virtual DOM
的解析和布局谈跛、UI 渲染。然而這一套解析塑陵,布局感憾,渲染的邏輯SDK基本實現(xiàn)了。
最后Weex
支持三端一致令花,服務器上的一份JS Bundle
阻桅,通過解析,實現(xiàn)iOS/Android/HTML5
三端的一致性兼都。
三嫂沉、為什么選擇用Flutter
目前跨端主流的框架Flutter
、Hybird
扮碧、RN
私股、Weex
浩淘。其中除了Flutter
耻瑟, 其他三個都屬于Web
型本辐,即HTML5
+ CSS
+ JavaScript
實現(xiàn)。
React-Native赖淤、Weex 核心是通過 Javascript 開發(fā)蜀漆,執(zhí)行時需要 Javascript 解釋器,UI是通過原生控件渲染漫蛔。Flutter 與用于構建移動應用程序的其它大多數(shù)框架不同嗜愈,因為 Flutter 既不使用WebView,也不使用操作系統(tǒng)的原生控件莽龟。 相反,F(xiàn)lutter 使用自己的高性能渲染引擎來繪制widget
锨天。Flutter 使用C毯盈、C ++、Dart 和 Skia
(2D渲染引擎)構建病袄。在 iOS上搂赋,F(xiàn)lutter 引擎的C/C ++ 代碼使用 LLVM 編譯,任何 Dart 代碼都是 AOT 編譯為本地代碼的益缠,F(xiàn)lutter 應用程序使用本機指令集運行(不涉及解釋器)脑奠。而在 Android 下,F(xiàn)lutter 引擎的 C/C ++ 代碼是用 Android 的NDK 編譯的幅慌,任何 Dart 代碼都是 AOT 編譯成本地代碼的宋欺,F(xiàn)lutter 應用程序依然使用本機指令集運行(不涉及解釋器)。因此,F(xiàn)lutter 能達到原生應用一樣的性能齿诞。
Web 型方案的優(yōu)點:
- 開發(fā)迅速
- 復用前端生態(tài)
- 支持熱更
Web 型方案的缺點:
- 一些復雜的交互無法帶來很好的體驗酸休,比如手勢、視頻播放祷杈。
- 在不打離線包的前提下斑司,進入頁面會有白屏。
- iOS 與Android 雙端渲染效果存在差異但汞。
跨端大生態(tài)
- JSCore 虛擬機(虛擬 DOM)
- Hybird
- React Native
- Weex
- Dart 虛擬機(自繪引擎)
1宿刮、Flutter 原理
相比 React Native
和 Weex
,Flutter
實現(xiàn)跨平臺采用了更為徹底的方案私蕾。它既沒有采用WebView
也沒有采用 JavaScript
糙置,而是自己實現(xiàn)了一臺UI框架,然后直接系統(tǒng)更底層渲染系統(tǒng)上畫UI是目。所以它采用的開發(fā)語言不是JS
谤饭,而是Dart
(Dart
是面向對象的、類定義的懊纳、單繼承的語言)揉抵。它的語法類似C語言,可以轉譯為JavaScript
嗤疯,支持接口(interfaces
)冤今、混入(mixins
)、抽象類(abstract classes
)茂缚、具體化泛型(reified generics
)戏罢、可選類型(optional typing
)和(sound type syste
)。 據(jù)稱Dart
語言可以編譯成原生代碼脚囊,直接跟原生通信龟糕。
同時,Flutter
將UI組件和渲染器從平臺移動到應用程序中悔耘,這使得它們可以自定義和可擴展讲岁。Flutter唯一要求系統(tǒng)提供的是canvas
,以便定制的UI組件可以出現(xiàn)在設備的屏幕上衬以,以及訪問事件(觸摸缓艳,定時器等)和服務(位置、相機等)看峻。這是Flutter
可以做到跨平臺而且高效的關鍵阶淘。另外Flutter
學習了RN
的UI編程方式,引入了狀態(tài)機互妓,更新UI時只更新最小改變區(qū)域溪窒。
系統(tǒng)的UI框架可以取代坤塞,但是系統(tǒng)提供的一些服務是無法取代的。Flutter
在跟系統(tǒng)service
通信方式霉猛,采用的是一種類似插件式的方式尺锚,或者有點像遠程過程調用RPC
方式,這種方式據(jù)說也要比RN的橋接方式高效惜浅。
2瘫辩、Flutter 和 React Native 底層框架對比
React-Native
、Weex
核心是通過 Javascript
開發(fā)坛悉,執(zhí)行時需要 Javascript
解釋器伐厌,UI 是通過原生控件渲染。Flutter
與用于構建移動應用程序的其它大多數(shù)框架不同裸影,因為 Flutter
既不使用 WebView
挣轨,也不使用操作系統(tǒng)的原生控件。 相反轩猩,Flutter
使用自己的高性能渲染引擎來繪制 widget
卷扮。Flutter
使用 C、C ++均践、Dart
和 Skia
(2D渲染引擎)構建晤锹。
Skia
是一個 2D的繪圖引擎庫,Chrome
和 Android
均采用 Skia
作為繪圖引擎彤委。Android
自帶了 Skia
鞭铆,所以 Flutter Android SDK
要比 iOS SDK
小很多。
在 ReactNative
中焦影,引入了虛擬 DOM
來減少DOM
的回流和重繪车遂,系統(tǒng)將虛擬 DOM
與真正的 DOM
進行比較,生成一組最小的更改斯辰,然后執(zhí)行這些更改舶担,以更新真正的 DOM
。最后椒涯,平臺重新繪制真實的 DOM
到畫布中柄沮。
React Native
是移動開發(fā)的一大進步,并且是 Flutter
的靈感來源废岂,但 Flutter
更進一步。 在 Flutter
中狱意,UI 組件和渲染器已經(jīng)從平臺中集成到用戶的應用程序中湖苞。沒有系統(tǒng) UI 組件可以操作,所以原來虛擬控件樹的地方現(xiàn)在是真實的控件樹详囤,Flutter
渲染 UI 控件樹并將其繪制到平臺畫布上财骨。
如果說非要比較 Flutter
和 React Native
的優(yōu)勢镐作,可以參考下面幾點:
UI 一致性
Flutter
因為是自己做的渲染,因此在iOS和Android的效果基本完全一致隆箩。 React Native
存在將RN
控件轉換為對應平臺原生控件的過程该贾,存在一定的差異。
動態(tài)化技術
Flutter
使用的Dart
語言捌臊,支持AOT
和JIT
兩種模式杨蛋,在Dev
時候,通過JIT
可以實現(xiàn)熱重載理澎,開發(fā)者可以即時的看到代碼修改的效果逞力。而在Release Build
的時候,通過AOT
事先編譯糠爬,來最大化的優(yōu)化性能寇荧。因此目前Flutter
不支持代碼的熱更新。
ReactNative
的代碼通過加載 JSBundle.js
執(zhí)行执隧,JSBundle.js
可以保存在本地揩抡,也可以通過遠程加載。目前有很多RN
的熱更新方案供選擇镀琉。
App體積
Flutter iOS
空項目 30M左右峦嗤,Android
空項目 7M左右。 (iOS需要額外集成Skia
) React Native iOS
空項目 3M左右滚粟,Android
20M左右寻仗。(Android
會加入OKHttp
導致體積增大)
Flutter
部分的底層功能在 Android
系統(tǒng)上已經(jīng)有實現(xiàn),因此 Android
上適配要好(RN
在 Android
上有可能遇到兼容性問題)凡壤。
Flutter的優(yōu)勢
運行效率上署尤,Flutter
和ReactNative
都可以達到理論上的60幀的刷新率,來實現(xiàn)「Native
般的流暢體驗」亚侠,Flutter
是全Native
在執(zhí)行曹体,基于底層代碼(Android
上為 C++ with NDK
,iOS 上為 C++ with LLVM
)硝烂,而ReactNative
是Native
控件 + JavaScript
代碼箕别,實際性能上,Flutter
應該優(yōu)于ReactNative
滞谢,據(jù)官方文檔串稀,Flutter
可以在支持的設備上達到120FPS,而ReactNative
的文檔上狮杨,只提到了可以達到60FPS母截。
兼容性上,Flutter
提供的 widget
都是基于 skia
來實現(xiàn)和精心定制的橄教,與具體平臺沒關清寇,所以能保持很高的跨 os
跨 os version
的兼容性喘漏。 Flutter
從更基礎的層去抹平平臺差異,站在了更寬廣华烟、更可控的一個基礎平臺上去演變和發(fā)展翩迈。 Flutter
官方提供了大部分 Material Design
控件的實現(xiàn)(甚至比 Android Design Support
實現(xiàn)的更多)。
四盔夜、Flutter開發(fā)語言Dart
1负饲、為什么要使用Dart語言
學習Flutter
就不得不提到Dart
,那Flutter
和Dart
有什么關系比吭?確實有關系绽族,早期的Flutter
團隊評估了十多種語言,并選擇了Dart
衩藤,因為它符合他們構建用戶界面的方式吧慢。
Dart
能成為Flutter
不可或缺的一部分,根本原因還是因為其具有以下特性:
-
Dart
是AOT
(Ahead Of Time
)編譯的赏表,編譯成快速检诗、可預測的本地代碼,使Flutter
幾乎都可以使用Dart
編寫瓢剿。這不僅使Flutter
變得更快逢慌,而且?guī)缀跛械臇|西(包括所有的小部件)都可以定制 -
Dart
也可以JIT
(Just In Time
)編譯,開發(fā)周期異臣淇瘢快攻泼,工作流顛覆常規(guī)(包括Flutter
流行的亞秒級有狀態(tài)熱重載) -
Dart
可以更輕松地創(chuàng)建以60fps運行的流暢動畫和轉場。Dart
可以在沒有鎖的情況下進行對象分配和垃圾回收鉴象。就像JavaScript
一樣忙菠,Dart
避免了搶占式調度和共享內存(因而也不需要鎖)。由于Flutter
應用程序被編譯為本地代碼纺弊,因此它們不需要在領域之間建立緩慢的橋梁(例如牛欢,JavaScript
到本地代碼)。它的啟動速度也快得多 -
Dart
使Flutter
不需要單獨的聲明式布局語言淆游,如JSX
或XML
傍睹,或單獨的可視化界面構建器,因為Dart
的聲明式編程布局易于閱讀和可視化犹菱。所有的布局使用一種語言拾稳,聚集在一處,Flutter
很容易提供高級工具腊脱,使布局更簡單 - 開發(fā)人員發(fā)現(xiàn)
Dart
特別容易學習熊赖,因為它具有靜態(tài)和動態(tài)語言用戶都熟悉的特性
2、編譯與執(zhí)行
歷史上虑椎,計算機語言分為兩組:靜態(tài)語言(例如C震鹉,其中變量類型是在編譯時靜態(tài)指定的)和動態(tài)語言(例如 Smalltalk
和JavaScript
,其中變量的類型可以在運行時改變)捆姜。靜態(tài)語言通常編譯成目標機器的本地機器代碼(或匯編代碼)程序传趾,該程序在運行時直接由硬件執(zhí)行。動態(tài)語言由解釋器執(zhí)行泥技,不產(chǎn)生機器語言代碼浆兰。
當然,事情后來變得復雜得多珊豹。虛擬機(VM
)的概念開始流行簸呈,它其實只是一個高級的解釋器,用軟件模擬硬件設備店茶。虛擬機使語言移植到新的硬件平臺更容易蜕便。因此,VM
的輸入語言常常是中間語言贩幻。例如轿腺,一種編程語言(如Java
)被編譯成中間語言(字節(jié)碼),然后在VM
(JVM
)中執(zhí)行丛楚。
另外族壳,現(xiàn)在有即時(JIT
)編譯器。JIT
編譯器在程序執(zhí)行期間運行趣些,即時編譯代碼仿荆。原先在程序創(chuàng)建期間(運行時之前)執(zhí)行的編譯器現(xiàn)在稱為AOT
編譯器。
一般來說坏平,只有靜態(tài)語言才適合AOT
編譯為本地機器代碼拢操,因為機器語言通常需要知道數(shù)據(jù)的類型,而動態(tài)語言中的類型事先并不確定功茴。因此庐冯,動態(tài)語言通常被解釋或JIT
編譯。
在開發(fā)過程中AOT
編譯坎穿,開發(fā)周期(從更改程序到能夠執(zhí)行程序以查看更改結果的時間)總是很慢展父。但是AOT
編譯產(chǎn)生的程序可以更可預測地執(zhí)行,并且運行時不需要停下來分析和編譯玲昧。AOT
編譯的程序也更快地開始執(zhí)行(因為它們已經(jīng)被編譯)栖茉。
相反,JIT
編譯提供了更快的開發(fā)周期孵延,但可能導致執(zhí)行速度較慢或時快時慢吕漂。特別是,JIT
編譯器啟動較慢尘应,因為當程序開始運行時惶凝,JIT
編譯器必須在代碼執(zhí)行之前進行分析和編譯吼虎。研究表明,如果開始執(zhí)行需要超過幾秒鐘苍鲜,許多人將放棄應用思灰。
3、Dart的編譯與執(zhí)行
在創(chuàng)造Dart
之前混滔,Dart
團隊成員在高級編譯器和虛擬機上做了開創(chuàng)性的工作洒疚,包括動態(tài)語言(如JavaScript
的V8引擎和Smalltalk
的Strongtalk
)以及靜態(tài)語言(如用于Java
的Hotspot
編譯器)。他們利用這些經(jīng)驗使Dart
在編譯和執(zhí)行方面非常靈活坯屿。
Dart
是同時非常適合AOT
編譯和JIT
編譯的少數(shù)語言之一(也許是唯一的“主流”語言)油湖。支持這兩種編譯方式為Dart
和(特別是)Flutter
提供了顯著的優(yōu)勢。
JIT
編譯在開發(fā)過程中使用领跛,編譯器速度特別快乏德。然后,當一個應用程序準備發(fā)布時隔节,它被AOT
編譯鹅经。因此,借助先進的工具和編譯器怎诫,Dart
具有兩全其美的優(yōu)勢:極快的開發(fā)周期瘾晃、快速的執(zhí)行速度和極短啟動時間。
Dart
在編譯和執(zhí)行方面的靈活性并不止于此幻妓。例如蹦误,Dart
可以編譯成JavaScript
,所以瀏覽器可以執(zhí)行肉津。這允許在移動應用和網(wǎng)絡應用之間重復使用代碼强胰。開發(fā)人員報告他們的移動和網(wǎng)絡應用程序之間的代碼重用率高達70%。通過將Dart
編譯為本地代碼妹沙,或者編譯為JavaScript
并將其與node.js
一起使用偶洋,Dart
也可以在服務器上使用。
最后距糖,Dart
還提供了一個獨立的虛擬機(本質上就像解釋器一樣)玄窝,虛擬機使用Dart
語言本身作為其中間語言。
Dart
可以進行高效的AOT
編譯或JIT
編譯悍引、解釋或轉譯成其他語言恩脂。Dart
編譯和執(zhí)行不僅非常靈活,而且速度特別快趣斤。
即使編譯后的代碼也可能需要一個接口來與平臺代碼進行交互俩块,并且這也可以稱為橋,但它通常比動態(tài)語言所需的橋快幾個數(shù)量級。另外玉凯,由于Dart
允許將小部件等內容移至應用程序中势腮,因此減少了橋接的需求。
4壮啊、布局
聲明式布局語言:
Center(child:
Column(children: [
Text('Hello, World!'),
Icon(Icons.star, color: Colors.green),
])
)