文章目錄
本文樣例都是使用的AndroidStudio,如果你使用Xcode或者vscode,代碼都是一樣的,只是IDE創建項目的方式以及運行按鍵位置不同而已。
1. 創建Flutter項目
AndroidStudio中選擇File
->New
->New Flutter Project
->Flutter Application
->NEXT
。接着填寫你的項目名稱等一系列信息後就創建成功了,我們就會看到AndroidStudio已經爲我們創建好了一個Demo,接着連上你的手機或者打開你的虛擬機,按下AndroidStudio的運行鍵,不一會兒,你就會驚喜的發現你的手機上就有一個Flutter計數器Demo了。
2. 介紹下AndroidStudio界面
這是我的AndroidStudio界面,接下來我分三個部分介紹下AndroidStudio的大致界面。
2.1 控制區
一次介紹每一個按鈕的功能。
- 第一個是用來選擇運行設備的,比方說我現在就選的是我的虛擬機,然後我按下運行後就可以將項目運行到我的虛擬機上而不會運行到連着我的電腦的手機上去;
- 第二個是選擇運行哪個Flutter module,如果你同一個項目裏面有多個module,你就可以在此選擇你想要運行的module;
- 第三個灰色的選項框我也沒弄懂她是幹嘛的,我至今都沒能選擇過,一直都是灰的;
- 綠色的三角形,大家熟知,運行鍵;
- 紅色的瓢蟲,大家熟知,debug鍵;
- 不知道幹嘛的;
- FlutterAPP的性能監視器;
- 閃電,這個是重點,也是Flutter的一大特性,熱重載鍵,他能做到不需要重新編譯代碼就能將你修改的代碼的效果在你的APP上顯示出來;
- 不知道幹嘛的;
- 紅色的正方形,停止運行按鈕。
2.2 Run運行區
就是Flutter的信息顯示區,類似於AndroidStudio的Logcat,能顯示FlutterAPP運行中的一些信息。
2.3 Flutter Outline/Flutter Inspector區
用於顯示當前界面的一些構建信息。
3. Flutter項目結構
我們挑一些重要的說一下:
- .idea文件夾,AndroidStudio識別項目的必備文件夾,不用管;
- Android文件夾,存放Flutter構建的Android項目的文件夾;
- ios文件夾,存放Flutter構建的iOS項目的文件夾;
- lib文件夾,存放Flutter項目和資源的文件夾;
- pubspec.yaml文件,存放Flutter項目相關信息,如項目名稱、版本、依賴等等,類似於Android項目的build.gradle文件。
4. main.dart文件
我們通過講這個文件來給大家大致介紹下Flutter項目代碼結構。
全部源代碼在此
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
4.1 import
首先我們看最開始的import
區。
這塊相當於C/C++的include
,反而不像java的import
。我爲什麼這麼說呢,你想一下,你寫java程序的時候,你是需要哪個類就直接在代碼中輸入類名,然後IDE會自動給你顯示有這個類的所有的包,然後讓你選包去導入;而寫dart是需要你先導入包,才能在代碼中寫這個包中的類,如果你沒有先導入包而直接到下面寫的話,IDE是不會提示你這個類可能會在哪個包中,而是直接報錯,這點和C/C++比較類似。
那我們爲什麼導入的是flutter/material.dart
這個包呢?我在第一節裏面說過,Flutter他內置了Android的Material Design風格和iOS的Cupertino風格的UI;所以這塊就是導入Material Design風格UI文件,而如果你要使用Cupertino風格UI文件的話,把它改成Cupertino就行了。
4.2 main()
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
-
第一行,指明項目的入口就是
MyApp()
。固定格式,可以不用管。 -
第二行就定義了一個類
MyApp
繼承自StatelessWidget
,並重寫了父類的build()
方法。Widget
可以看成Flutter中的頁面,只要是Flutter中的頁面,都必須繼承自Widget
。他有點類似於Android中的View
,但是不同於View
的是,Flutter中的padding
、align
、layout
等居然也是Widget
。 -
如果是
StatelessWidget
,則代表她是一個“無狀態”的Widget
,我的理解就是狀態相當於Widget
的一些數值,比方說頁面要顯示計數器的計數count
,那麼這個count
就是一個狀態,只要有狀態就使用StatefulWidget
。像MyApp
它沒有狀態,於是就用StatelessWidget
。 -
繼承自
StatelessWidget
的類必須實現build()
方法,相當於這個類是一個死頁面,只需要展示固定的內容,也就是不需要狀態,所以直接通過build()
直接寫入界面就行。 -
build()
方法必須同樣返回一個Widget
,所以我們就使用MaterialApp
,其中我們給他的title
、theme
、home
進行了賦值,同學們應該都能大致讀懂啥意思,首頁home
則給了MyHomePage
.
4.3 MyHomePage
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
4.3.1 MyHomePage
我們在前面說過,如果一個頁面有數據也就是“狀態”的話,那麼他就得繼承自StatefulWidget
。
如果一個類繼承自StatefulWidget
,那這個類會很簡單,只需要創建一個構造方法,構造方法中寫入key
以及該Widget
需要的數據。然後重寫createState()
方法。
4.3.2 MyHomePageState
如果一個類繼承自StatefulWIdget
,那麼一定會有一個他的State
類並繼承自State<該類>
,就像class _MyHomePageState extends State<MyHomePage>
一樣。
那我們來看看State類裏面有些啥東西:
首先先定義“狀態”:由於我們這個APP主要的功能是用來計數,所以必須定義一個int型變量來計數:
int _counter = 0;
接着如果我們這個_counter變量變了,那就得通知flutter說狀態變了,需要更新UI:
void _incrementCounter() {
setState(() {
_counter++;
});
}
其中,setState()
方法就是用來通知Flutter
這個狀態改變了,要去更新UI的。
最後重寫build()
方法來寫入界面:
Scaffold
是一個組件,它提供了默認的導航欄、標題和包含主屏幕widget
樹(後同“組件樹”或“部件樹”)的body
屬性。body
後面是一個Center
組件,它的作用是將它的子Widget
定位到父Widget
的中間。Center
後面是一個Column
組件,這個組件類似於Android中的LinearLayout
的orientation: Vertical
,也就是垂直向的線性佈局。同時Flutter也提供了Row
這個水平向的線性佈局。他們的子Widget
是children
屬性,也就是可以寫多個Widget
。Column
裏面是兩個Text
,這個沒啥講的- 接下來是一個
FloatingActionButton
,這就是一個浮動按鈕,Android裏面有這個控件,核心是他的onPressed
屬性,這個就相當於onClick()
,用於處理點擊事件。
5. 體驗熱重啓
首先先讓項目在虛擬機或者手機上運行着,然後我們把頁面Text中的"You have pushed the button this many times:“改爲"You have clicked the button this many times:”,然後按熱重啓鍵(macOS版AndroidStudio默認是commond+s鍵),接着你就能裏面在虛擬機或者手機上看到修改之後的結果。