官术网_书友最值得收藏!

1.4 第一個應用——計數器

在真正領略Flutter的風采之前,我們可以參考本書的附錄A安裝Flutter開發環境。完成安裝操作之后,讀者現在就可以跟隨本節的內容嘗試在沒有Dart語言基礎的情況下理解Flutter默認實現的一個計數器應用,你會發現一切都比你想象中的簡單很多。

1.4.1 創建第一個應用

為了使各個階段的開發者都能夠輕松地完成本書中的操作,本書將會統一采用更加輕量的Visual Studio Code作為編寫代碼和展示示例的IDE,并且使用macOS進行演示(Windows系統中的操作與之類似)。可以按照如下步驟創建第一個Flutter應用。

(1)啟動Visual Studio Code。

(2)選擇菜單欄中的“查看”→“命令面板”,如圖1.6所示,打開命令面板。

圖1.6 選擇“查看”→“命令面板”

(3)在命令面板中輸入“flutter”,并選擇下拉列表框中的“Flutter: New Project”,如圖1.7所示,新建一個Flutter項目。

圖1.7 選擇下拉列表框中的“Flutter: New Project”

(4)輸入自定義的項目名稱(如hello_world),如圖1.8所示,按Return鍵創建項目。

圖1.8 輸入項目名稱

(5)單擊Select a folder to create the project in按鈕(見圖1.9),指定項目將要放置的位置,這里選擇目錄后,單擊OK按鈕。

圖1.9 單擊Select a folder to create the project in按鈕

(6)等待項目創建結束之后,新項目窗口便會自動打開。

1.4.2 Flutter項目的結構

創建Flutter項目后,可以在Visual Studio Code中看到Flutter項目的結構,如圖1.10所示。

圖1.10 Flutter項目的結構

部分文件夾的作用如下。

  • android文件夾:存放Flutter與Android原生交互的代碼,該文件夾下的文件和單獨創建的Android項目基本一樣。
  • ios文件夾:對于標準的iOS項目,存放Flutter與iOS原生交互的代碼。
  • lib文件夾:Flutter的核心目錄,存放的是使用Dart語言編寫的代碼。不管是Android平臺,還是iOS平臺,安裝、配置開發環境后,都可以在對應的設備或模擬器上面運行這里的Dart代碼,而整個應用的入口是lib文件夾下的main.dart文件。也可以在這個lib文件夾下面創建不同的文件夾,里面存放了不同的文件來管理日益壯大的應用。
  • test文件夾:存放Flutter的測試代碼。

注意,pubspec.yaml文件是項目的配置文件,可以在該文件中聲明項目中使用到的依賴庫、環境版本以及資源文件等。附錄A會介紹更多相關內容。

pubspec.yaml的另一個重要功能便是指定應用中需要使用的本地資源(圖片、字體、音頻、視頻等)。通常情況下,我們會在項目根目錄下創建一個images目錄,用來存放應用中會使用到的圖片資源,這些圖片資源需要在該配置文件中的assent屬性下聲明(見圖1.11)。

圖1.11 pubspec.yaml中的資源文件聲明

應用運行在設備上之后,這些資源文件就會一并打包在安裝程序中,在之后的章節會對配置文件的其他配置項做具體的介紹。

熟悉了這些文件夾的大致作用之后,我們先嘗試運行一下這個默認的項目。為此,我們需要啟動模擬器或者使用USB接口接入真機。具體步驟如下。

(1)模擬器打開或者真機接入后,在Visual Studio Code主界面右下角的狀態欄中選擇可以運行的目標設備(見圖1.12)。

圖1.12 選擇可用設備

(2)打開lib文件夾下的main.dart文件,按F5鍵或選擇菜單欄中的“調試”→“啟動調試”,開始運行項目(見圖1.13)。

圖1.13 選擇“調試”→“啟動調試”

(3)等待應用在模擬器或真機上自動啟動。

(4)如果一切正常,在應用安裝成功后,我們應該就能夠在設備上看到圖1.14所示的計數器應用。

圖1.14 計數器應用

此時,我們的第一個應用就已經啟動了,你可以看到這個應用的首頁展示了一個標準的Material Design風格的界面,頂部有一個帶有頁面標題的導航欄,右下角有一個帶有“+”號的懸浮按鈕,單擊這個按鈕就會使頁面中的數字增加。這個應用可以用來記錄單擊按鈕的次數。

1.4.3 計數器應用的實現

已經運行的計數器應用是我們步入Flutter殿堂的階梯。通過分析這個應用的實現方式,我們會對Flutter中的應用開發有一個直觀的理解。

首先,打開lib文件夾下的main.dart文件,這里面存放了這個計數器應用的所有代碼。忽視注釋中的內容,我們可以在文件的最上方看到帶有import字樣的代碼行,它的作用是導入該文件需要使用到的庫。這里我們導入了Material庫,因為我們需要使用該這個庫下面的UI組件。下面我們可以看到一個main()函數,它是Dart語言的主函數,每當我們運行應用后,系統都會首先調用main.dart文件中的這個函數。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

main()函數中調用了runApp()函數,我們可以將runApp()理解為運行Flutter應用的入口,而傳入的MyApp對象就代表了需要運行的應用。在Flutter中,MyApp又稱為組件對象,它在這里就相當于應用顯示在屏幕上的UI組件,應用啟動后就能夠顯示MyApp中的內容。下面是MyApp組件的具體實現。

class MyApp extends StatelessWidget {

  // 重寫StatelessWidget的build()方法,返回一個組件對象
  @override
  Widget build(BuildContext context) {
    /*
    * MaterialApp表明應用采用Material Design風格,
    * 可以在theme屬性下配置應用中與主題相關的屬性,如顏色、按鈕風格
    * */
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

通過閱讀上面的代碼,我們發現類MyApp繼承自StatelessWidget,并重寫了它的build()方法,這個方法返回了一個組件對象,所以這里我們可以推理出MaterialApp()也是一個組件對象。前面已經提到了“一切皆為組件”,讀者可以從這里開始隨著閱讀本書慢慢地理解這句話了,它是我們開發出用戶能看見的應用的基礎,我們可以通過設置組件的屬性來控制應用所能展示的內容。

繼續分析下面的代碼,我們可以看到在MaterialApp組件中有3個屬性,分別是title、theme、home。其中,title表示組件的標題屬性;theme可以用來配置應用的主題樣式;home參數用來指定MaterialApp中的主體內容,它接受另一個組件,這里指定為MyHomePage。在使用MyHomePage時,還傳入了一個title參數,它用來接受顯示在計數器應用頂部導航欄中的標題。我們可以嘗試修改這個值然后保存代碼,如果程序依然處于運行狀態,由于Flutter支持熱加載的特性,導航欄中的文字就會實時更新為最新的值,這個特性能夠幫助我們更高效地開發應用。

繼續向下,我們就可以看到MyHomePage組件的具體實現了。

class MyHomePage extends StatefulWidget {
  // 構造函數,用于接受調用者的參數
  MyHomePage({Key key, this.title}) : super(key: key);

  // 聲明了一個字符串類型的final變量,并在構造函數中初始化
  final String title;

  /*
  * 所有繼承自StatefulWidget的組件都要重寫createState() 方法,
  * 用于指定該頁面的狀態是由誰來控制的。
  * 在Dart中,以下劃線開頭的變量和方法的默認訪問權限就是私有的,
  * 類似于Java中用private關鍵字修飾的變量和方法,只能在類的內部訪問
  */
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

/*
* State是一個狀態對象,<> 里面表示該狀態是與誰綁定的。
* 在修改狀態時,在該類中進行編寫
*/
class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  // 實現計數值加1的函數
  void _incrementCounter() {
    // setState方法用于更新屬性
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    /* 
    * Scaffold是一個Material Design風格的組件,
    * 它繼承自StatefulWidget,包含appBar、body、drawer等屬性
    * */
    return Scaffold(
      /* 頂部導航欄 */
      appBar: AppBar(
        /*
        * 這里的Widget其實就是MyHomePage,
        * 它在這里調用了上面傳遞過來的title變量
        */
        title: Text(widget.title),
      ),
     // Scaffold中的主體布局
      body: Center(
        /*
        * 在Center組件中有一個child屬性,用來定義它的子組件Column,
        * Column表示以行的形式顯示其子組件
        */
        child: Column(
          /*
          * mainAxisAlignment用來控制子組件的對齊方式,
          * 也可以把值設置為start、end等
          */
          mainAxisAlignment: MainAxisAlignment.center,
           /* 
           * Column組件的children屬性用于指定它的子組件,
           * 它接受一個數組,可以向該屬性傳遞多個組件
           */
          children: <Widget>[
            // Text組件,用于顯示文本
            Text(
              'You have pushed the button this many times:',
            ),
            // Text組件,使用style屬性來設置它的樣式
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      /*
      * FloatingActionButton也是Material Design風格的組件,
      * 可以在onPressed屬性中定義其單擊事件
      */
      floatingActionButton: FloatingActionButton(
        // 通過單擊觸發_incrementCounter函數
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        // 指定child的子組件為一個“+”號圖標
        child: Icon(Icons.add),
      ),
    );
  }
}

MyHomePage是實現計數器應用的核心,它同樣是一個組件,最終會顯示在應用中。在_MyHomePageState中,我們可以重寫build()方法,返回MyHomePage組件中顯示的內容。根據注釋,我們可以在代碼中找到顯示在屏幕中的組件,其中涉及了Scaffold、Column、Text等常用組件,以及對FloatingActionButton響應事件的處理。Dart語言的相關語法和組件的具體含義會在下面的章節中介紹。

在上述代碼中,很多組件都有child屬性,如FloatingActionButton組件中的child屬性是一個“+”圖標,它就表示將“+”圖標設置為FloatingActionButton的子組件,表現在屏幕上的效果就是“+”圖標顯示在FloatingActionButton中。通過這種方法,我們可以將多個組件組合在一起而開發出一個完整的頁面。

另外,讀者還可能注意到一個重要的部分,MyHomePage繼承自StatefulWidget,MyApp也繼承自一個與它類似的StatelessWidget。作為計數器應用的核心組件,MyHomePage用于改變計數值。也就是說,當單擊“+”按鈕后,增加計數這個功能需要由它負責。要想達到這樣的效果,必然就需要改變_counter變量的值,StatefulWidget是可以改變它對應State對象中的值的一個組件,而StatelessWidget不具備這個功能,它只能用來展示UI。第3章會具體介紹StatefulWidget和StatelessWidget這兩個類的具體用法。

主站蜘蛛池模板: 贡觉县| 长泰县| 巩义市| 酒泉市| 巴彦淖尔市| 海安县| 保德县| 西充县| 盐山县| 宜川县| 新兴县| 赤壁市| 石景山区| 高密市| 北川| 成安县| 张家港市| 昭平县| 英德市| 淮滨县| 大悟县| 民县| 余姚市| 平山县| 彰化市| 班玛县| 巧家县| 德保县| 通化县| 赤水市| 重庆市| 金阳县| 灵石县| 邹平县| 莱阳市| 克东县| 铜鼓县| 洛浦县| 金溪县| 额尔古纳市| 宿州市|