Google Flutter From Scratch:使用小部件構建應用程序
Flutter正迅速成為開發跨平台移動應用程序的最流行框架之一。今天,大多數Android和iOS開發人員開始認為,它是一種比其他跨平台框架(如React Native和NativeScript)更快,更具面向未來的替代方案。
谷歌本身不遺餘力地吸引更多開發者加入。例如,Google I / O今年有幾個深入的會議,專註於使用它開發符合Material Design標準的應用程序。在其中一次會議中,Google還宣布Flutter將成為Material Design的一流平台。
在本系列教程中,我將幫助您掌握使用Flutter開發Android應用程序的基礎知識。在本系列開始的教程中,我將重點關注Flutter小部件,這是所有Flutter應用程序的構建塊。
先決條件
要充分利用這個系列,您需要:
- 最新版本的Android Studio
- 運行Android API等級21或更高版本的設備或模擬器
1.配置Android Studio
安裝了一些輕量級插件後,您可以使用Android本地Android應用程序開發人員最熟悉的Android Studio來開發Flutter應用程序。
首先啟動Android Studio,然後 在歡迎屏幕中選擇配置>插件選項。
在彈出的對話框中,按「 瀏覽存儲庫」 按鈕並搜索Flutter插件。

找到插件後,按「 安裝」 按鈕。此時,系統會詢問您是否還要安裝Dart插件。按是 繼續。

插件依賴項對話框
安裝 完兩個插件後,按「 重啟Android Studio」按鈕完成配置。
2.創建一個新項目
重啟後,您將能夠 在Android Studio歡迎屏幕上看到「 啟動新的Flutter項目」按鈕。按此按鈕開始創建您的第一個Flutter項目。
在下一個屏幕上,選擇Flutter Application 選項,然後按Next。

您現在將看到一個表單,詢問有關Flutter應用程序的各種詳細信息,例如其名稱和位置。確保在所有欄位中鍵入有效值。

Flutter插件不與Flutter SDK捆綁在一起。因此,您必須單獨安裝SDK。您現在可以通過按「 安裝SDK」 按鈕來執行此操作。
根據Internet連接的速度,安裝可能需要相當長的時間才能完成。成功後,您將能夠按「 下一步」 按鈕完成項目設置。
3.添加入口點
在本教程中,您將在lib / main.dart 文件中編寫代碼。默認情況下,它將包含一些您不需要的示例代碼。所以在繼續之前刪除所有內容。
Flutter框架使用Dart編程語言,這是一種易於學習的語言,其語法與Java和C的語法非常相似。因此,像大多數獨立的Java和C程序一樣,Flutter應用程序也需要一個main()
函數,一個特殊的函數,作為應用程序的入口點。
因此,將以下代碼添加到main.dart 文件中:
void main() {
// TO DO
}
此時,您可以按 Shift-F10 來構建和運行應用程序。如果您在前面的步驟中沒有遇到任何錯誤,您應該會看到該應用在您的設備上顯示空白的白色畫布。
4.使用無狀態小部件
所有Flutter應用程序都由一個或多個小部件組成,類的實例允許您在屏幕上繪製文本和圖像。通常,您不必從頭開始編寫任何低級小部件,因為該框架附帶了各種預製的,漂亮的小部件,這些小部件遵循Android和iOS平台的設計語言。
為了能夠在您的應用程序中使用基本小部件,請widgets 通過在main.dart 文件的開頭添加以下代碼來導入庫:
import package:flutter/widgets.dart;
您可以創建的最簡單的小部件是無狀態小部件。正如您可能已經猜到的那樣,它們沒有與之相關的狀態,因此是靜態的。它們非常適合顯示標籤,標題和其他UI元素,其內容在應用程序運行時不太可能發生變化。要創建無狀態窗口小部件,必須擴展StatelessWidget 該類並覆蓋其build() 方法。以下示例代碼顯示了如何:
class MyFirstWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
// More code here
}
}
正如您在上面的代碼中看到的,該build() 方法必須返回一個Widget 對象。您可以自由選擇並返回Flutter提供的數十種預製小部件中的任何一種。例如,如果要顯示一行文本,可以創建並返回一個Text 小部件,如下所示:
return Text("This is nice!",
textDirection: TextDirection.ltr);
請注意,您必須始終記住在使用Text 窗口小部件時指定文本的方向 。
但是,如果您立即運行該應用程序,您將無法看到該文本。那是因為你還沒有實例化你的無狀態小部件。所以轉到main() 方法,在其中實例化小部件,並將其傳遞給runApp() 方法。這是如何做:
runApp(new MyFirstWidget());
在您添加上述代碼並保存項目的那一刻,Android Studio應該會自動在您的設備上熱重新載入應用,以便您查看文本。

如果要顯示圖像而不是文本,可以Text
使用Image
類的build()
方法中的窗口小部件替換窗口小部件。以下代碼顯示如何創建Image
下載並顯示遠程圖像的窗口小部件:
`return` `Image.network(`
`"[https://images.pexels.com/photos/1168940/pexels-photo-1168940.jpeg](https://images.pexels.com/photos/1168940/pexels-photo-1168940.jpeg)"``);`
再次保存項目時,您應該在設備上看到類似的內容:

5.創建小部件樹
所有Flutter應用程序都可以被視為小部件樹。您在上一步中創建的應用程序是一個只包含一個小部件的小部件樹。但是,使用Text
或Image
窗口小部件作為窗口小部件樹的頂部元素並不是一個好主意,因為您將無法向它們添加任何子窗口小部件。
Flutter提供了幾個可以作為其他小部件容器的小部件。最常用的是Row
和Column
小部件。正如他們的名字所暗示的那樣, Row
小部件允許您將多個小部件放在一起,並且Column
小部件可以幫助您將小部件放在 另一個之下。在創建更深層的窗口小部件樹時,它們是必不可少的。
以下代碼顯示如何使用Column
窗口小部件創建具有兩個子窗口的窗口小部件樹:Text
窗口小部件和Image
窗口小部件。
`Text myText = Text(``"This is a nice photo!"``,`
`textDirection: TextDirection.ltr);`
`Image myImage = Image.network(`
`"[https://images.pexels.com/photos/1168940/pexels-photo-1168940.jpeg](https://images.pexels.com/photos/1168940/pexels-photo-1168940.jpeg)"``);`
`return` `Column(`
`children: <Widget>[myText, myImage]`
`);`
該應用程序現在應該如下所示:

此外,還有一些小部件可以幫助您更好地定位單個小部件。例如,Center
窗口小部件可幫助您集中窗口小部件。同樣,Container
窗口小部件允許您向窗口小部件添加填充和邊距。
以下代碼向您展示如何Column
通過將您剛創建的窗口小部件嵌入窗口小部件來居中它Center
:
return Center(child: Column(
children: <Widget>[myText, myImage],
mainAxisSize: MainAxisSize.min
)
);
在上面的代碼中,請注意Column 窗口小部件使用一個名為的附加屬性 mainAxisSize,其值設置為min。這是必要的,因為在對列居中之前,必須使其高度等於其所有子節點的高度之和。如果沒有該屬性,Column 窗口小部件將與設備的屏幕一樣大,並且Center 窗口小部件將不會對其產生任何影響。
6.使用Material Design Widgets
在此期間,您一直在使用作為widgets 庫的一部分的基本小部件。Flutter有一個名為的替代庫material,它提供了Material Design小部件。要在您的應用程序中使用它,請使用以下內容替換導入widgets 庫的語句:
import package:flutter/material.dart;
接下來,要將Material Design樣式應用於窗口小部件,您必須MaterialApp 在窗口小部件樹的頂部放置一個 窗口小部件。您還必須將先前創建的所有小部件嵌入到窗口小Scaffold 部件中,該窗口小部件可用作窗口小部件的主屏幕 MaterialApp 。
此外,由於大多數Material Design應用程序都有應用欄,因此您可以選擇將Scaffold 小部件appBar 屬性設置為新AppBar 小部件。
以下代碼向您展示如何簡潔地完成所有操作:
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text("My App")),
body: Center(
child: Column(
children: <Widget>[myText, myImage],
mainAxisSize: MainAxisSize.min
),
)
)
);
該應用程序現在應該看起來好多了。

7.使用有狀態小部件
無狀態小部件是不可變的。使用您在前面的步驟中編寫的代碼,沒有簡單的方法來修改Text
窗口小部件或Image
窗口小部件的內容。為什麼?因為Flutter框架更喜歡反應式編程而不是命令式編程。因此,它的大多數小部件都沒有可以在運行時更新其內容的setter方法。例如,Text
窗口小部件沒有setText()
允許您更改其顯示文本的方法。
另一方面,有狀態小部件是可變的,儘管不是直接的。他們依靠 State
對象來決定在任何給定實例中應該顯示什麼。因此,只要State
對象發生更改,框架就會自動更新連接到它的任何有狀態窗口小部件的內容。
要創建有狀態窗口小部件,必須擴展StatefulWidget
該類並覆蓋其 createState()
方法。
class MySecondWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TO DO
}
}
接下來,您必須創建一個新的自定義State 類,其中包含構成有狀態窗口小部件狀態的變數。此外,在類中,您必須重寫 build() 方法以返回窗口小部件樹。
以下代碼顯示如何創建State 包含名為的單個變數的類url:
`class` `MyState` `extends` `State<MySecondWidget> {`
`String url =` `"[https://source.unsplash.com/random/800x600](https://source.unsplash.com/random/800x600)"``;`
`// A random image from Unsplash`
`@override`
`Widget build(BuildContext context) {`
`// More code here`
`}`
`}`
為了一個具體的例子,我們現在創建一個Material Design窗口小部件樹Image ,其中包含一個顯示隨機圖像的RaisedButton 窗口小部件和一個窗口小部件,用戶可以按這個窗口小部件來載入新的隨機圖像。以下代碼顯示了如何:
return MaterialApp(
home: Scaffold(
body: Center(
child:Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
RaisedButton(
child: Text("Press Me"),
onPressed: changeURL,
),
Image.network(url)
]
)
)
)
);
請注意,Image 窗口小部件的構造函數現在將url 變數作為其輸入,而不是字元串文字。這允許框架在Image 繪製窗口小部件時使用變數的最新值。
另請注意,RaisedButton 窗口小部件具有onPressed 指向名為的事件偵聽器的屬性changeURL()。該方法尚不存在,因此請創建它。
void changeURL() {
// More code here
}
當然,在方法中,您必須更改url
變數的值。但是,您不應該直接更改它。如果這樣做,Flutter框架將不會收到有關更改的通知。要正確更新有狀態窗口小部件的狀態,必須始終在setState()
方法內進行所有更改。
目前,為了顯示隨機圖像,我建議您使用Unsplash Source 服務。從中下載隨機圖像所需要做的就是向其URL發出HTTP請求並向其傳遞唯一的查詢字元串。
以下代碼顯示如何使用時間戳構造唯一查詢字元串:
`setState(() {`
`url =` `"[https://source.unsplash.com/random/800x600/?](https://source.unsplash.com/random/800x600/?)"` `+`
`"q=${new DateTime.now().millisecondsSinceEpoch}"``;`
`});`
此時,您的自定義State 類已準備就緒。接下來需要做的就是實例化它並從createState() 有狀態小部件的方法返回它。
runApp(new MyFirstWidget());
如果您將有狀態窗口小部件的實例傳遞給runApp()
方法,重新載入應用程序,並按幾次按鈕,您應該會看到它每次都顯示一張新照片。

結論
您現在知道如何在Flutter應用程序中使用無狀態和有狀態的小部件。您還學習了如何將Material Design主題應用於它們,動態更改其內容並使它們具有交互性。
值得注意的是,Flutter不使用任何移動平台的本機小部件。它使用名為Skia的高性能2D圖形引擎自行繪製所有小部件,該引擎廣泛使用GPU。因此,Flutter應用程序通常以接近60 fps的速度運行,並且感覺非常流暢和響應。
知乎關注我:私信回復「資料」獲取高級UI、Gradle、RxJava、小程序、Hybrid、移動架構、React Native、性能優化等技術教程!架構師課程、NDK、混合式開發全方 面的 Android高級實踐技術講解性能優化架構思維導圖,和BATJ面試題及答案。

推薦閱讀: