上一節(jié),我們完成了Flutter的環(huán)境搭建。本節(jié),我們開(kāi)始搭建項(xiàng)目,簡(jiǎn)單了解Flutter及其基礎(chǔ)組件。
- 項(xiàng)目創(chuàng)建
1.1 命令行創(chuàng)建
1.2 Android Studio創(chuàng)建 - 熟悉工程
2.1 簡(jiǎn)單實(shí)現(xiàn)
2.2 熟悉widget
2.3 Text
2.4 MaterialApp
2.5 ListView 列表視圖 - 常用基礎(chǔ)組件
3.1 基礎(chǔ)文本
3.2 富文本
3.3 基礎(chǔ)容器Container
1. 項(xiàng)目創(chuàng)建
1.1 命令行創(chuàng)建
以前
不支持駝峰寫(xiě)法,需要通過(guò)小寫(xiě)字母+下劃線_命名,但是現(xiàn)在支持哦
flutter create flutter_demo
- 創(chuàng)建成功

- 按照指令,到
指定文件夾去運(yùn)行項(xiàng)目:
cd FlutterDemo
flutter run
注意:
- 如果此時(shí)
未打開(kāi)模擬器,會(huì)提示需要選擇一個(gè)模擬器。- 如果此時(shí)打開(kāi)了
多個(gè)模擬器,也會(huì)提示您選中一個(gè)模擬器來(lái)運(yùn)行。
image.png選中模擬器后,flutter會(huì)自動(dòng)使用Xcode工具進(jìn)行編譯。
image.png- 如果需要
真機(jī)調(diào)試,我們需要手動(dòng)打開(kāi)項(xiàng)目工程,去Xcode配置證書(shū)
終端運(yùn)行Flutter命令鍵:Flutter run key commands. r Hot reload. ?????? 熱重載(比對(duì)被修改部分,更新被修改代碼) R Hot restart. 熱重啟(所有資源重新加載) h Repeat this help message. d Detach (terminate "flutter run" but leave application running). c Clear the screen q Quit (terminate the application on the device). s Save a screenshot to flutter.png. b Toggle the platform brightness setting (dark and light mode). (debugBrightnessOverride) w Dump widget hierarchy to the console. (debugDumpApp) t Dump rendering tree to the console. (debugDumpRenderTree) L Dump layer tree to the console. (debugDumpLayerTree) S Dump accessibility tree in traversal order. (debugDumpSemantics) U Dump accessibility tree in inverse hit test order. (debugDumpSemantics) i Toggle widget inspector. (WidgetsApp.showWidgetInspectorOverride) I Toggle oversized image inversion ???. (debugInvertOversizedImages) p Toggle the display of construction lines. (debugPaintSizeEnabled) o Simulate different operating systems. (defaultTargetPlatform) z Toggle elevation checker. g Run source code generators. M Write SkSL shaders to a unique file in the project directory. v Launch DevTools. P Toggle performance overlay. (WidgetsApp.showPerformanceOverlay) a Toggle timeline events for all widget build methods.
- 如果使用
安卓模擬器,可以在頂部控制欄配置模擬器:
image.png選中模擬器,運(yùn)行:
image.png
- 由于
個(gè)人習(xí)慣,我更喜歡在Xcode中開(kāi)發(fā),在終端使用命令運(yùn)行。執(zhí)行flutter run時(shí),會(huì)讓我們選擇想使用的模擬器(后續(xù)我主要使用iPhone模擬器)。
1.2 Android Studio創(chuàng)建
- 除了使用
flutter create命令創(chuàng)建項(xiàng)目,我們還可使用Android Studio創(chuàng)建,也可以使用VSCode創(chuàng)建,它們都有flutter插件。
- 啥? 你問(wèn)
Xcode是否可以創(chuàng)建?
想想蘋(píng)果與谷歌的競(jìng)爭(zhēng)者關(guān)系,就知道蘋(píng)果不可能做這樣的支持插件的。??
1.2.1 使用Android Studio創(chuàng)建

-
四種創(chuàng)建方式:

-
項(xiàng)目
基本信息
image.png -
項(xiàng)目
唯一標(biāo)識(shí)和支持的平臺(tái)
image.png -
點(diǎn)
Finish后,會(huì)進(jìn)行網(wǎng)絡(luò)請(qǐng)求,拉取資源,創(chuàng)建成功。
(如果沒(méi)配置鏡像,拉取資源非常緩慢。 上一節(jié)有介紹如何配置鏡像)
image.png
坑點(diǎn)
如果Android Studio正在運(yùn)行項(xiàng)目,我們command + Q強(qiáng)制退出。下次打開(kāi)Android Studio時(shí),會(huì)回到當(dāng)時(shí)的緩存。如果緩存成功找回,會(huì)運(yùn)行正常。如果緩存找不到,會(huì)導(dǎo)致無(wú)法運(yùn)行,而且新建工程也無(wú)法運(yùn)行。處理方式:
刪除flutter目錄下cache緩存文件夾中的lockfile文件,再運(yùn)行項(xiàng)目即可。(相當(dāng)于XCode的Clean操作)# pwd請(qǐng)?zhí)鎿Q為自己flutter的文件目錄 rm /pwd/flutter/bin/cache/lockfile
2. 熟悉工程
-
創(chuàng)建項(xiàng)目后,可以看到main.dart有很多代碼。我們最快熟悉的方式是:全部刪除,手動(dòng)實(shí)現(xiàn)并分析:
image.png
2.1 簡(jiǎn)單實(shí)現(xiàn)
Flutter中,我們使用的開(kāi)發(fā)語(yǔ)言是Dart,現(xiàn)在我們先體驗(yàn),完整的Dart語(yǔ)法,我們可以去官網(wǎng)了解
- 手動(dòng)實(shí)現(xiàn):
// 以下代碼,均使用Dart語(yǔ)言編寫(xiě)
// 資源包 (可以理解為我們iOS的UIKit)
import 'package:flutter/material.dart';
// main入口函數(shù) (就像iOS main.m中的main函數(shù))
void main() {
// runApp(app); // runApp就像iOS的 UIApplication, 而app就像我們的根控制器
// flutter中沒(méi)有控制器和視圖的概念,都是widget組件。
runApp(
Center( //我們用Center部件,自動(dòng)居中展示。這是Center的構(gòu)造函數(shù)
// child就像subView
// Text是一種文本框樣式,設(shè)置默認(rèn)值和顯示方向(ltf: left to right 從左到右)
child: Text('Hello', textDirection: TextDirection.ltr,),
)
);
}
- flutter
運(yùn)行,文本框成功展示:
image.png
2.2 熟悉widget
Widget: 作用類似于OC中的UIView,是小部件。分為兩大類:
StatelessWidget:無(wú)狀態(tài)組件??旖萱Istless。
創(chuàng)建后就決定了樣式,狀態(tài)更改需要手動(dòng)創(chuàng)建新widget。StatefulWidget: 有狀態(tài)組件。快捷鍵stful。
本質(zhì)上也是無(wú)狀態(tài)組件,渲染時(shí)無(wú)狀態(tài),因?yàn)?code>UI本身是無(wú)狀態(tài)的。但它會(huì)保留組件狀態(tài),記錄組件狀態(tài)的屬性改變時(shí),會(huì)自動(dòng)重新渲染。直到該組件完全銷毀,才會(huì)釋放記錄的屬性
2.2.1 無(wú)狀態(tài)組件(StatelessWidget)
- 我們將
main入口的Center組件改成自定義的MyWidget無(wú)狀態(tài)組件。
import 'package:flutter/material.dart';
void main() {
runApp(
MyWidget(), //()是構(gòu)造函數(shù),類似C++。
);
}
// 無(wú)狀態(tài)Widget快捷鍵是 stless
// 一個(gè)Widget,就是一個(gè)class類
class MyWidget extends StatelessWidget {
@override
// build:會(huì)將小部件放到渲染樹(shù)中去
// 渲染樹(shù): 會(huì)從main入口的第一個(gè)widget開(kāi)始渲染,然后以樹(shù)結(jié)構(gòu)依次向下渲染組件
// 所有widget都必須有build方法,build返回的是什么,MyWidget在外界渲染的就是什么
Widget build(BuildContext context) {
return Center(
child: Text(
'Hello Flutter2',
textDirection: TextDirection.ltr,
),
);
}
}
- 選擇
模擬器,debug運(yùn)行,模擬器啟動(dòng)后,可以修改文本內(nèi)容,點(diǎn)擊熱重載按鈕,感受熱重載的強(qiáng)大。

reload熱重載功能,是通過(guò)比較新舊代碼變化,來(lái)更新被改動(dòng)部分代碼的。 但是有些場(chǎng)景下熱重載是失敗的,只能restart重啟才可以。具體場(chǎng)景,參考Flutter官網(wǎng)介紹
Dart語(yǔ)言簡(jiǎn)寫(xiě):
- Dart語(yǔ)言中,如果
函數(shù)只有一行內(nèi)容時(shí),可以使用=>縮寫(xiě):// 改動(dòng)前 //void main() { // runApp(MyWidget()); //} // 簡(jiǎn)寫(xiě): void main() => runApp(MyWidget());
2.3 Text
-
Text是一個(gè)文本組件,是StatelessWidget不可變組件。
2.3.1 構(gòu)造函數(shù)與參數(shù)
- 以
Text為例,構(gòu)造函數(shù)是Text(),包含必選參數(shù)和可選值,可選值可以賦默認(rèn)值:
image.png
2.3.2 final和const修飾符
final和const都類似于Swift的let,是不可變的。
-
final可以不賦初始值,運(yùn)行時(shí)再賦值。 -
const必須在創(chuàng)建時(shí)就賦值。
比如Text中使用頻率最高的style和textAlign,都是final聲明,因?yàn)?code>Text本身是StatelessWidget不可變的組件。

- 給
Text加入樣式,使用變量創(chuàng)建TextStyle,_下劃線表示私有變量
import 'package:flutter/material.dart';
// 入口,展示MyWidget組件
void main() => runApp(MyWidget());
class MyWidget extends StatelessWidget {
@override
// build 確定組件返回的內(nèi)容
Widget build(BuildContext context) {
// final創(chuàng)建一個(gè)_textStyle不可變變量,_開(kāi)頭的屬性,表示私有屬性
final _textStyle = TextStyle(color: Colors.red, fontSize: 40.0, fontWeight: FontWeight.bold);
return Center(
child: Text(
'Hello Flutter',
textDirection: TextDirection.ltr,
style: _textStyle, // 直接使用變量
),
);
}
}
Text和TextStyle相關(guān)屬性和參數(shù),可以Command + 鼠標(biāo)左鍵查看

2.4 MaterialApp
-
MaterialApp:Flutter推薦方式,提供快速構(gòu)建APP的方式(包括導(dǎo)航欄、內(nèi)容、主題等)
home: 類似于根控制器,需要指定一個(gè)widget
Scaffold: 類似于導(dǎo)航控制器NavigationController,包含導(dǎo)航欄相關(guān)屬性。是一個(gè)可變組件statefulWidget
appBar:導(dǎo)航欄
body: 內(nèi)容theme:主題,可控制主題色
import 'package:flutter/material.dart';
// 入口,展示MyWidget組件
void main() => runApp(App());
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
// MaterialApp:Flutter推薦方式,提供快速構(gòu)建APP的方式(包括導(dǎo)航欄、內(nèi)容、主題等)
return MaterialApp(
// home: 類似于根控制器,也是需要指定一個(gè)widget
// Scaffold: 類似于導(dǎo)航控制器NavigationController,包含導(dǎo)航欄相關(guān)屬性。是一個(gè)可變組件statefulWidget
home: Scaffold(
// appBar:導(dǎo)航欄
appBar: AppBar(
title: Text('Flutter Demo'),
),
// body: 內(nèi)容
body: MyWidget(),
),
// theme:主題,可控制主題色
theme: ThemeData(
primaryColor: Colors.yellow
),
);
}
}
class MyWidget extends StatelessWidget {
@override
// build 確定組件返回的內(nèi)容
Widget build(BuildContext context) {
// final創(chuàng)建一個(gè)_textStyle不可變變量,_開(kāi)頭的屬性,表示私有屬性
final _textStyle = TextStyle(color: Colors.red, fontSize: 40.0, fontWeight: FontWeight.bold);
return Center(
child: Text(
'Hello Flutter',
textDirection: TextDirection.ltr,
style: _textStyle, // 直接使用變量
),
);
}
}

2.5 ListView 列表視圖
-
列表視圖:類似iOS的UITableView,但是沒(méi)有Section的概念。
2.5.1 準(zhǔn)備Model
在布局之前,先準(zhǔn)備數(shù)據(jù):
- 新建
Model文件夾,新建car.dart文件:
image.png
// 不需要導(dǎo)入material.dart,因?yàn)镃ar直接繼承Object
// Car 模型
class Car {
// 構(gòu)造函數(shù): {}內(nèi)是可選值
const Car({
this.name,
this.imageUrl,
});
// 名稱
final String name;
// 圖片鏈接
final String imageUrl;
}
final List<Car> datas = [
Car(
name: '保時(shí)捷918 Spyder',
imageUrl:
'https://upload-images.jianshu.io/upload_images/2990730-7d8be6ebc4c7c95b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
Car(
name: '蘭博基尼Aventador',
imageUrl:
'https://upload-images.jianshu.io/upload_images/2990730-e3bfd824f30afaac?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
Car(
name: '法拉利Enzo',
imageUrl:
'https://upload-images.jianshu.io/upload_images/2990730-a1d64cf5da2d9d99?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
Car(
name: 'Zenvo ST1',
imageUrl:
'https://upload-images.jianshu.io/upload_images/2990730-bf883b46690f93ce?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
Car(
name: '邁凱倫F1',
imageUrl:
'https://upload-images.jianshu.io/upload_images/2990730-5a7b5550a19b8342?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
),
Car(
name: '薩林S7',
imageUrl:
'https://upload-images.jianshu.io/upload_images/2990730-2e128d18144ad5b8?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240',
)
];
2.5.2 設(shè)置ListView
- 如果直接導(dǎo)入
Car模型,需要導(dǎo)入頭文件
三種導(dǎo)入
頭文件的方式
直接手寫(xiě),在頂部import左鍵點(diǎn)擊Car,出現(xiàn)紅色小燈泡,點(diǎn)擊import Library鼠標(biāo)光標(biāo)放在Car上,按住Option+Enter鍵,再按一次Enter鍵,可快捷導(dǎo)入import Libraryfinal List<Car> datas = []
-
Container: 類似于html的div,也類似于iOS的UIView,就是用來(lái)放東西的。需要設(shè)置大小(也可以被子控件撐出大?。?/li> -
Column: 內(nèi)容垂直排列的容器 -
row: 內(nèi)容水平排列的容器 -
stack: 內(nèi)容重疊的容器 -
Image:圖片的可變組件,network加載網(wǎng)絡(luò)圖片 -
SizedBox:空容器,有大小。(有時(shí)為了便于內(nèi)部插入元素,會(huì)直接使用Container) -
MaterialApp的debugShowCheckedModeBanner:隱藏導(dǎo)航欄Debug角標(biāo)
import 'package:flutter/material.dart';
import 'Model/car.dart';
// 入口,展示MyWidget組件
void main() => runApp(App());
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
// MaterialApp:Flutter推薦方式,提供快速構(gòu)建APP的方式(包括導(dǎo)航欄、內(nèi)容、主題等)
return MaterialApp(
// 隱藏導(dǎo)航欄Debug角標(biāo)
debugShowCheckedModeBanner: false,
// home: 類似于根控制器,需要指定一個(gè)widget
home: Home(),
// theme:主題,可控制主題色
theme: ThemeData(
primaryColor: Colors.yellow
),
);
}
}
// Home 組件
class Home extends StatelessWidget {
// 回調(diào)函數(shù),返回widget組件
Widget _cellForRow(BuildContext context, int index) {
// Container類似于html的div,也類似于iOS的UIView,就是用來(lái)放東西的
// 需要大?。ㄒ部梢员蛔涌丶纬龃笮。? return Container(
color: Colors.white,
// height: 20,
margin: EdgeInsets.all(10), //EdgeInsets.only(top: 1),
// 子控件
// Column 內(nèi)容垂直排列的容器 row 內(nèi)容水平排列的容器 stack 內(nèi)容重疊的容器
// Image圖片可變組件,network加載網(wǎng)絡(luò)圖片
child: Column(
children: <Widget>[
Image.network(datas[index].imageUrl),
SizedBox(height: 8,),
Text(
datas[index].name,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
fontStyle: FontStyle.italic),),
SizedBox(height: 8,)
]
)
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],
appBar: AppBar(
title: Text("Flutter Demo"),
),
// ListView 列表組件(沒(méi)有iOS的Section概念)
body: ListView.builder(
// cell個(gè)數(shù)
itemCount: datas.length,
// cell內(nèi)容(等同與cellForRow)build 是渲染
// iOS中是使用代理和協(xié)議完成,這里是直接使用回調(diào)函數(shù),有兩個(gè)入?yún)? itemBuilder: _cellForRow,
),
);
}
}
// 模型數(shù)組
// 沒(méi)導(dǎo)入頭文件時(shí),會(huì)提示需要導(dǎo)入Car頭文件
// 三種導(dǎo)入頭文件的方式
// 1. 直接手寫(xiě),在頂部import
// 2. 左鍵點(diǎn)擊Car,出現(xiàn)紅色小燈泡,點(diǎn)擊import Library
// 3. 鼠標(biāo)光標(biāo)放在Car上,按住Option+Enter鍵,再按一次Enter鍵,可快捷導(dǎo)入import Library
// final List<Car> datas = []
-
效果展示:
image.png 實(shí)際開(kāi)發(fā)中,我們可以將
ListView內(nèi)容抽離出來(lái),做成單獨(dú)文件listView_demo.dart:
import 'package:flutter/material.dart';
import 'car.dart';
class ListViewDemo extends StatelessWidget {
// 回調(diào)函數(shù),返回widget組件
Widget _cellForRow(BuildContext context, int index) {
return Container(
color: Colors.white,
margin: EdgeInsets.all(10)
child: Column(
children: <Widget>[
Image.network(datas[index].imageUrl),
SizedBox(height: 8,),
Text(
datas[index].name,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
fontStyle: FontStyle.italic),),
SizedBox(height: 8,)
]
)
);
}
@override
Widget build(BuildContext context) {
return ListView.builder(
// cell個(gè)數(shù)
itemCount: datas.length,
itemBuilder: _cellForRow,
);
}
}
- 在
main.dart中,直接使用我們封裝的ListViewDemo(導(dǎo)入頭文件)即可:
import 'package:flutter/material.dart';
import 'Model/listView_demo.dart';
// 入口,展示MyWidget組件
void main() => runApp(App());
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
// MaterialApp:Flutter推薦方式,提供快速構(gòu)建APP的方式(包括導(dǎo)航欄、內(nèi)容、主題等)
return MaterialApp(
// 隱藏導(dǎo)航欄Debug角標(biāo)
debugShowCheckedModeBanner: false,
// 根組件
home: Home(),
// 主題
theme: ThemeData(
primaryColor: Colors.yellow
),
);
}
}
// Home 組件
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],
appBar: AppBar(
title: Text("Flutter Demo"),
),
// 列表
body: ListViewDemo(),
);
}
}
3. 常用基礎(chǔ)組件
- 上面講了
簡(jiǎn)單封裝,我們現(xiàn)在對(duì)幾個(gè)基礎(chǔ)組件進(jìn)行簡(jiǎn)單封裝:
3.1 基礎(chǔ)文本
- 新建一個(gè)
base_widget.dart文件,創(chuàng)建TextDemo組件:
- 通過(guò)
屬性聲明變量(內(nèi)容和樣式),_開(kāi)頭的屬性為私有屬性。$+屬性名:快捷插入變量內(nèi)容。 如果后面有其他字符等信息,可使用{}包裹起來(lái)。Text可設(shè)置maxLines最大行數(shù),超出部分樣式通過(guò)overflow設(shè)置(ellipsis為尾部省略號(hào))
import 'package:flutter/material.dart';
//【普通文本 Demo】
class TextDemo extends StatelessWidget {
// 文本樣式(私有屬性)
final TextStyle _textStyle = TextStyle(
fontSize: 24.0,
);
final String _title = 'Flutter入門(mén)';
final String _author = 'HT';
@override
Widget build(BuildContext context) {
// $ + 屬性名: 快捷插入變量?jī)?nèi)容。 如果后面有其他字符等信息,可使用{}包裹起來(lái)。
return Text(
'《$_title》這是一個(gè)TextDemo,使用Flutter開(kāi)發(fā)。由iOS開(kāi)發(fā)者${_author}開(kāi)發(fā),快速配置,簡(jiǎn)易上手的零基礎(chǔ)學(xué)習(xí)方式。歡迎閱讀和上手練習(xí),不懂之處,留言交流',
textAlign: TextAlign.center,
style: _textStyle,
maxLines: 4, // 最多4行
overflow: TextOverflow.ellipsis, // 超出顯示省略號(hào)
);
}
}
- 在
main.dart中指定body為TextDemo:
image.png -
展示樣式:
image.png
3.2 富文本
- 使用
RichText組件,通過(guò)給text指定TextSpan類型,添加children:<TextSpan>數(shù)組,數(shù)組內(nèi)創(chuàng)建TextSpan,并賦值樣式即可:
import 'package:flutter/material.dart';
//【富文本 Demo】
class RichTextDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RichText(
//基礎(chǔ)元素
text: TextSpan(
text: '《Flutter 入門(mén)》',
style: TextStyle(
fontSize: 30,
color: Colors.black,
) ,
// 子元素
children:<TextSpan>[
// 元素一
TextSpan(
text: 'HT',
style: TextStyle(
fontSize: 20,
color: Colors.blue,
),
),
// 元素二
TextSpan(
text: '666',
style: TextStyle(
fontSize: 40,
color: Colors.red,
),
),
]),
);
}
}
- 在
main.dart中指定body為RichTextDemo:
image.png -
展示樣式:
image.png
3.3 基礎(chǔ)容器Container
- 創(chuàng)建基礎(chǔ)組件
BaseWidgetDemo,返回Container組件:
//【基礎(chǔ)組件Demo】
class BaseWidgetDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 容器背景藍(lán)色(沒(méi)有給定大小時(shí),根據(jù)子視圖大小撐開(kāi))
return Container(
color: Colors.blue,
// 子視圖橫向布局
child: Row(
children: <Widget>[
Container(
// 內(nèi)邊距
padding: EdgeInsets.only(left: 10,top: 10,right: 10,bottom: 10),
// 外邊距
margin: EdgeInsets.only(left: 10,top: 10,right: 10,bottom: 10),
// 子元素紅色
color: Colors.red,
// 子元素內(nèi)容包含?號(hào)圖片
child: Icon(Icons.add),
),
Container(
// 子元素紅色
color: Colors.red,
// 子元素內(nèi)容包含?號(hào)圖片
child: Icon(Icons.add),
),
],
),
);
}
}

-
展示樣式:
image.png
Dart中沒(méi)有iOS的Button概念:
因?yàn)?code>Button實(shí)際是圖片+文字+手勢(shì)+狀態(tài)組成,以及封裝相應(yīng)的響應(yīng)事件。我們一般使用手勢(shì)小部件,包裝圖片和文字即可。
【快捷鍵】
command+option+L:自動(dòng)格式化
command+-:折疊當(dāng)前函數(shù)
command+shift+-:折疊全部函數(shù)
command+{:回到上一步
command+}: 回到下一步
command+shift+O: 快速到指定文件
stless:不可變組件
stful: 可變組件
本節(jié)主要是Flutter的基礎(chǔ)體驗(yàn),通過(guò)本節(jié),其實(shí)我們已經(jīng)感受到了Flutter的便捷。
下一節(jié),Flutter入門(mén)三:自動(dòng)布局(Row/Column/Stack)與兩種Widget
















