[譯] 如何用 Flutter 來建立一個帶有底部導航欄的應用程式

elang發表於2019-03-04

[譯] 如何用 Flutter 來建立一個帶有底部導航欄的應用程式

如果你從事移動開發,你可能聽說過谷歌的跨平臺 SDK:Flutter。Flutter 的 beta 版本 於 2 月 27 日釋出,並於近期釋出了第一個預覽版。為了幫助您開始使用 Flutter,本教程將介紹 SDK 的一些基本內容,同時還將介紹如何設定底部導航欄。為了幫助您學習,本教程的程式碼可以在 GitHub上獲得。

什麼是 Flutter?

在我們開始編寫程式碼之前,讓我們先談談什麼是 Flutter。Flutter SDK 繼承了一套完整的開發框架,包括在 Android 和 iOS 上構建原生移動應用所需的 widget 和工具。與其他諸如 React Native 和 Xamarin 等跨平臺框架的區別在於,它不使用平臺原生 widget,也不使用 webview。相反,Flutter 有自己的用 C/C++ 編寫的渲染引擎,而用來編寫 Flutter 應用程式的 Dart 程式碼在各個平臺上都可以編譯成底層程式碼。這就可以在每個平臺上都能做出高效能的應用。不僅應用在使用體驗上非常快,而且通過 Flutter 的熱過載特性也大大加快了開發時間。熱過載允許開發人員在他們的裝置或模擬器上立即顯示修改內容的變化效果,由此可以減少那些浪費在等待程式碼編譯的時間。

如何建立一個 Flutter 應用

現在我們已經瞭解了 Flutter 是什麼,讓我們開始建立我們的應用程式。如果您還沒有準備好開發環境,請按照 Flutter 網站的步驟安裝 Flutter SDK。要建立應用程式,請執行“flutter create my_app”。如果您想讓您的應用程式使用 Swift 或 Kotlin 作為平臺特定程式碼,那麼您可以從終端或命令列執行“flutter create -i Swift -a Kotlin my_app”。開啟你建立的新專案,你可以使用安裝了 Dart 外掛的 VS Code 或者安裝了 Flutter 和 Dart 外掛的 Android Studio。如果您需要編輯器安裝的相關幫助,請參考 Flutter 的 幫助文件

第一步 定義入口點

讓我們從開啟 main.dart 檔案開始,該檔案位於 lib/ 目錄下。接下來,由於我們要從頭開始編寫應用程式,所以刪除檔案中的所有程式碼。這個檔案是我們應用程式的入口點。在檔案的開始編寫:

import 'package:flutter/material.dart';
複製程式碼

這就匯入了 Flutter SDK 提供的 Material Design widgets。如果您想檢視所有提供的 widget,可以在 Widget 目錄 中檢視。

在匯入語句之後,我們需要新增 main 方法。

void main() => runApp(App());
複製程式碼

如果您在新增 main 方法後看到一些錯誤,不要擔心。這是因為我們還沒有建立傳遞給 runApp 函式的 App widget 類。runApp 函式接收一個型別為 Widget 的類,並將它作為 root widget 執行。

現在我們要建立我們的 App widget。還是在 main.dart 裡面,在 main 方法下面新增以下的程式碼。

class App extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
   return MaterialApp(
     title: 'My Flutter App',
     home: Home(),
   );
 }
}
複製程式碼

這就建立了一個新的無狀態 widget App。之所以是一個無狀態 widget,因為它的構建方法中沒有任何內容會依賴於狀態更新。所有的 StatelessWidgets 都需要實現 build 方法,因為這是我們建立使用者介面的地方。在我們的 App widget 中,我們簡單地建立了一個新的 MaterialApp,並將 Home 屬性設定為我們希望顯示的第一個頁面或 widget。在本例中,我們把它設定為 Home widget,我們將在接下來建立這個 widget。

第二步 建立主頁

lib 目錄下,建立一個新檔案,並將其命名為 home_widget.dart。在這個檔案的頭部,我們需要再次匯入 material widgets。

import 'package:flutter/material.dart';
複製程式碼

接下來,我們將建立作為我們主頁的 widget。為此,我們將建立一個新的 StatefulWidget。當使用者介面需要根據應用程式的當前狀態發生變化時,StatefulWidget 就派上用場了。例如,現在我們要使用底部導航欄,我們的 Home widget 將根據當前選定的選項卡來渲染出不同的 widget。首先,在匯入語句下面新增以下程式碼。

class Home extends StatefulWidget {
 @override
 State<StatefulWidget> createState() {
    return _HomeState();
  }
}
複製程式碼

您可能會注意到,這個 widget 類沒有實現我們前面提到的 build 方法。當涉及到 StatefulWidgets 時,build 方法會在 widget 對應的 State 類中實現。在 StatefulWidget 中,唯一需要的方法是我們在上面實現的 createState 方法,我們只返回一個 _HomeState 類例項。類名前面的 “_” 代表 Dart 將類或類屬性標記為 private。我們現在需要建立 home widget 的 state 類。在 home_widget.dart 檔案的末尾新增這個段程式碼:

class _HomeState extends State<Home> {
 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       title: Text('My Flutter App'),
     ),
     bottomNavigationBar: BottomNavigationBar(
       currentIndex: 0, // this will be set when a new tab is tapped
       items: [
         BottomNavigationBarItem(
           icon: new Icon(Icons.home),
           title: new Text('Home'),
         ),
         BottomNavigationBarItem(
           icon: new Icon(Icons.mail),
           title: new Text('Messages'),
         ),
         BottomNavigationBarItem(
           icon: Icon(Icons.person),
           Title: Text('Profile')
         )
       ],
     ),
   );
 }
}
複製程式碼

這裡有很多內容,我們來逐一看看。在 _HomeState 類中,我們實現了 Home widget 的 build 方法。我們從 build 方法返回的 widget 叫做 Scaffold。這個 widget 有一些很棒的屬性,可以幫助我們佈置主螢幕,包括新增底部導航欄、滑動條和選項卡。我們現在只使用它的 appBarbottomNavigationBar 屬性。在我們的底部導航欄中,我們返回一個列表,其中列出了我們希望在底部欄中出現的專案。如您所見,我們有三個選項卡,分別是 Home、Message 和 Profile。我們還將當前索引作為屬性設定為 0。稍後我們將把它與當前選項卡聯絡起來。當前索引可以讓導航欄知道要將哪個圖示用於當前選擇的選項卡。

此時,我們差不多已經準備好第一次執行 Flutter 應用了,來看看我們的成果。再回到 main.dart 檔案,在頂部,我們需要匯入新建立的 Home widget。我們可以通過在當前的匯入語句下新增下面這個匯入語句來實現。

import 'home_widget.dart';
複製程式碼

我們現在應該可以執行我們的應用了。你可以在 VS Code 裡面,任意的 Dart 檔案裡按 F5,或者在 Android Studio 中點選 run 按鈕,或者在終端中輸入 flutter run。如果您需要模擬器安裝或者模擬執行應用程式的相關幫助,請參考 Flutter 的幫助文件。如果一切順利,你的應用應該是這樣的。

flutter1

太棒了!我們現在已經有一個應用程式了,而且它有很漂亮的底部導航欄。然而,這裡有一個問題。我們的導航欄不會導引到任何地方!現在讓我們解決這個問題。

第三步 準備導航

回到 home_widget.dart 檔案,我們需要對 _HomeState 類做一些更改。在類的頂部,我們需要新增兩個新的例項屬性。

 class _HomeState extends State<Home> {
  int _currentIndex = 0;
  final List<Widget> _children = [];
...
複製程式碼

第一個是當前所選選項卡的索引,另一個則是選項卡對應的希望渲染的 widget 列表。

接下來,我們需要使用這些屬性來告訴我們的 widget,當一個新選項卡被選中時需要顯示什麼。為此,我們需要對 build 方法返回的 scaffold widget 進行一些更改。這是我們新的 build 方法。

@override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       title: Text('My Flutter App'),
     ),
     body: _children[_currentIndex], // new
     bottomNavigationBar: BottomNavigationBar(
       onTap: onTabTapped, // new
       currentIndex: _currentIndex, // new
       items: [
         new BottomNavigationBarItem(
           icon: Icon(Icons.home),
           title: Text('Home'),
         ),
         new BottomNavigationBarItem(
           icon: Icon(Icons.mail),
           title: Text('Messages'),
         ),
         new BottomNavigationBarItem(
           icon: Icon(Icons.person),
           title: Text('Profile')
         )
       ],
     ),
   );
 }
複製程式碼

我們的 build 方法中更改的三行用 // new 註釋了。首先,我們新增了 scaffold 的 body 屬性,即在應用程式欄和底部導航欄之間顯示的 widget。我們將 body 設定為與 _children widget 列表中相對應的 widget。接下來,我們給底部導航欄新增 onTap 屬性。我們將它設定為一個名為 ontabtap 的函式,該函式將接收被選中選項卡的索引並決定如何處理它。我們馬上就實現這個函式。最後,我們將底部導航欄的 currentIndex 設定為 state 類裡面的 _currentIndex 屬性。

第四步 處理導航

現在,我們將新增上一步中提到的 ontabtap 函式。在 _HomeState 類的底部新增以下函式。

void onTabTapped(int index) {
   setState(() {
     _currentIndex = index;
   });
 }
複製程式碼

這個函式接收被選中選項卡的索引,並在我們的 state 類上呼叫 setState。這將觸發 build 方法接收我們傳遞給它的狀態資訊並再次執行。在本例中,我們將傳遞更新的選項卡索引,該索引將更改 scaffold widget 的 body,並啟用導航欄上正確的選項卡。

第五步 新增子 widgets

我們的應用程式就要完成了。最後一步是建立 _children widget 列表中用到的 widget 並把它們新增到導航欄。首先 在 lib 目錄下建立一個名為 placeholder_widget.dart 的新檔案。這個檔案將作為一個簡單的 StatelessWidget 來使用背景色。

import 'package:flutter/material.dart';

class PlaceholderWidget extends StatelessWidget {
 final Color color;

 PlaceholderWidget(this.color);

 @override
 Widget build(BuildContext context) {
   return Container(
     color: color,
   );
 }
}
複製程式碼

現在我們要做的就是嚮導航欄中新增 PlaceholderWidget。在 home_widget.dart 的頂部,需要匯入我們的 widget。

import 'placeholder_widget.dart';
複製程式碼

然後,我們要做的就是將這些 widget 新增到 _children 列表中,以便在選擇新選項卡時渲染它們。

class _HomeState extends State<Home> {
 int _currentIndex = 0;
 final List<Widget> _children = [
   PlaceholderWidget(Colors.white),
   PlaceholderWidget(Colors.deepOrange),
   PlaceholderWidget(Colors.green)
 ];
...
複製程式碼

就是這樣!現在應該可以執行應用程式並在選項卡之間切換了。如果您想要看到 Flutter 的熱過載特性,請嘗試更改一下 BottomNavigationBarItems。值得注意的是,更改傳遞給 PlaceholderWidgets 的顏色不會在熱過載期間反映出來,因為 Flutter 會保持我們 StatefulWidget 的狀態。

image1

結論

在本教程中,我們學習瞭如何搭建一個新的 Flutter 應用程式並讓底部導航欄工作。像 Flutter 這樣的跨平臺工具在移動領域越來越流行,因為它們縮短了開發時間。Flutter 有它的獨特之處,因為它不需要使用 底層原生的 widget 或 webview。目前採用 Flutter 的主要缺點之一是在功能特性上缺少第三方支援。然而,Flutter 仍然是一種很有前途的工具,使用它可以在不犧牲效能的前提下編寫出非常棒的跨平臺應用程式。

如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章