一. 創建Flutter項目
1.1. 創建
命令行方式
flutter create learn_flutter
注意:
- Flutter的名稱不要包含特殊的字符,另外 <font color=red>不可以使用駝峯,不支持大寫,儘量不要使用一些符號</font> 標識
- 創建完之後使用自己喜歡的開發工具打開即可
- xxx_xxx 下劃線格式較多一些
工具創建
如:android studio - Start a new Flutter project
1.2. 運行
運行
命令行方式,進入flutter項目目錄:flutter run即可
android studio 打開項目,可以使用ide提供的快捷工具直接運行,as也是可以運行ios模擬器的
也可以通過as或xcode分別打開flutter項目中的android或ios代碼,直接運行即可。
as也可以直接打開整個flutter項目代碼
斷點
vscode dart代碼支持斷點調試的,也是代碼面板左邊點擊某行代碼打上斷點,然後run - start debugging
二. 目錄結構
文件或目錄 | 說明 |
---|---|
.dart_tool | 記錄了一些dart工具庫所在的位置和信息 |
.idea | android studio 是基於idea開發的,.idea 記錄了項目的一些文件的變更記錄 |
android | Android項目文件夾 |
ios | iOS項目文件夾 |
lib | lib文件夾內存放我們的dart語音代碼 |
test | 用於存放我們的測試代碼 |
.gitignore | git忽略配置文件 |
.metadata | IDE 用來記錄某個 Flutter 項目屬性的的隱藏文件 |
.packages | pub 工具需要使用的,包含 package 依賴的 yaml 格式的文件 |
flutter_app.iml | 工程文件的本地路徑配置 |
pubspec.lock | 當前項目依賴所生成的文件 |
pubspec.yaml | 當前項目的一些配置文件,包括依賴的第三方庫、圖片資源文件等 |
README.md | READEME文件 |
重要的文件就以下幾個:
- lib
我們日常開發的dart語言代碼都放在這裏,可以說是我們的“核心工作文件夾”
- iOS
這裏麪包含了iOS項目相關的配置和文件,當我們的項目需要打包上線的時候,需要打開該文件內的Runner.xcworkspace文件進行編譯和打包工作。
- android
與ios文件夾一樣,在android項目需要打包上架的時候,也需要使用此文件夾裏面的文件。同樣的如果我們需要原生代碼的支持,原生代碼也是放在這裏。
- test
這裏存放了我們在項目開發過程中的測試代碼,良好的測試習慣是保證代碼質量的必要手段,希望大家在test文件裏寫更多的代碼!
- pubspec.yaml
就好比開發原生,你總要知道工程如何配置,依賴三方,資源文件等
2.1. main.dart
flutter 默認入口文件,內部main函數是flutter解析的入口
關於默認的main.dart文件:
1、程序默認入口文件,這個是可配置的,如as開發環境:可以通過Edti Configuratios來修改入口文件。。。也可以通過命令行:flutter run -t lib/entry.dart
2、雖然入口文件能修改,但是一般不用,並且注意,入口文件內必須有main函數主入口的,這個跟android,ios之類的一樣
三. hot reload & hot restart
冷啓動
從零編譯運行,耗時
hot reload
主要執行build:
@override
Widget build(BuildContext context) {
意思就是如果修改的是build方法體內的內容,只需要hot reload即可
hot restart
重新運行整個app,如果修改的是非build內容,則需要hot restart
四. flutter
4.1. 基本頁面
void main() {
runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('title'),
),
body: Center(
child: Text(
'hello world',
style: TextStyle(
color: Colors.amber,
fontSize: 50
),
strutStyle: StrutStyle(
fontSize: 10,
fontStyle: FontStyle.italic,
),
textDirection: TextDirection.ltr,
// textScaleFactor: 2,
)
),
bottomNavigationBar: BottomAppBar(
color: Colors.red,
child: Text(
'bottom'
),
),
)
)
);
}
4.2. 代碼分析
runApp
runApp是Flutter內部提供的一個函數,當我們啓動一個Flutter應用程序時就是從調用這個函數開始的
- 我們可以點到runApp的源碼,查看到該函數
該函數讓我們傳入一個東西:Widget?
widget
- 我們學習Flutter,從一開始就可以有一個基本的認識:Flutter中萬物皆Widget(萬物皆可盤);
- 在我們iOS或者Android開發中,我們的界面有很多種類的劃分:應用(Application)、視圖控制器(View Controller)、活動(Activity)、View(視圖)、Button(按鈕)等等;
- 但是在Flutter中,這些東西都是不同的Widget而已;
- 也就是我們整個應用程序中所看到的內容幾乎都是Widget,甚至是內邊距的設置,我們也需要使用一個叫Padding的Widget來做;
material
- material是Google公司推行的一套設計風格,或者叫設計語言、設計規範等;
- 裏面有非常多的設計規範,比如顏色、文字的排版、響應動畫與過度、填充等等;
- 在Flutter中高度集成了Material風格的Widget;
- 在我們的應用中,我們可以直接使用這些Widget來創建我們的應用(後面會用到很多);
cupertino.dart 風格
前端開發,ui是主要部分,上面的Material提供了豐富的ui組件,cupertino風格是蘋果風格的,但不是很豐富,可以嘗試用
Scaffold 腳手架
- 翻譯過來是腳手架,腳手架的作用就是搭建頁面的基本結構;
- 所以我們給MaterialApp的home屬性傳入了一個Scaffold對象,作爲- 啓動顯示的Widget;
- Scaffold也有一些屬性,比如appBar和body;
- appBar是用於設計導航欄的,我們傳入了一個title屬性;
- body是頁面的內容部分,我們傳入了之前已經創建好的Center中包裹的一個Text的Widget;
4.3. 代碼重構
一個簡單的頁面,嵌套寫了那麼多層的代碼,很不友好,所以,正常的代碼怎麼做的?
flutter中萬物皆widget,也即分析頁面後,可以將頁面元素拆分,比如:導航條,body體,底部視圖等。然後各個部分抽離出來封裝爲新的組件
4.3.1. 封裝widget
首先,新入門語言,都會覺得有些不是因,要做的是需要熟悉寫法,學會該語言的代碼結構,然後熟練就好了。
關於flutter的widget,先說明一下:
- Flutter整個開發過程中就是形成一個Widget樹,所以形成嵌套是很正常的。
- 封裝widget有兩種類型,可以繼承自StatelessWidget或者StatefulWidget
這裏先不深入如何完全自定義widget,先學會小視圖組合方式的封裝,把代碼重構清晰
4.3.1.1. StatelessWidget
StatelessWidget是沒有狀態改變的Widget,通常這種Widget僅僅是做一些展示工作而已;
- 它們的數據通常是直接寫死(放在Widget中的數據,必須被定義爲final)
- StatelessWidget所繼承的Widget被@immutable標記,表示不可變,不可變是指該widget內所有的變量是不可變的,所以,你的widget內聲明狀態是不合理的。所以印證了上面的話:StatelessWidget類型的widget只做一些純展示
- 很重要的一點是:自定義widget內沒有setState方法,所以,沒法進行widget狀態管理,觸發重新渲染更新
- 從parent widget中傳入的而且一旦傳入就不可以修改;
- 從InheritedWidget獲取來使用的數據;
//1、繼承自StatelessWidget
//2、重寫的方法:build方法
class MyStatelessWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return <返回我們的Widget要渲染的Widget,比如一個Text Widget>;
}
}
build
- Flutter在拿到我們自己創建的StatelessWidget時,就會執行它的build方法;
- 我們需要在build方法中告訴Flutter,我們的Widget希望渲染什麼元素,比如一個Text Widget;
- StatelessWidget沒辦法主動去執行build方法,當我們使用的數據發生改變時,build方法會被重新執行;
build 什麼情況會執行:
- 1、當我們的StatelessWidget第一次被插入到Widget樹中時(也就是第一次被創建時);
- 2、當我們的父Widget(parent widget)發生改變時,子Widget會被重新構建;
- 3、如果我們的Widget依賴InheritedWidget的一些數據,InheritedWidget數據發生改變時;
重構結果
篇幅原因,部分代碼就不展示了
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage()
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('title'),
),
body: HomeBody(),
bottomNavigationBar: HomeBottomBar(),
);
}
}
class HomeBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text(
'hello world',
...
)
);
}
}
class HomeBottomBar extends StatelessWidget {...}
4.3.1.2. StatefulWidget
StatefulWidget是需要保存狀態,並且可能出現狀態改變的Widget;前面說了,StatelessWidget是純展示的一個widget,也即其是沒辦法做狀態管理的,所以,其上內容是沒法更新的。就做一些靜態展示。。與其相對的額StatefulWidget就包含了狀態管理,做數據展示和數據操作