flutter,跟著官網一步一步創建第一個flutter應用

  • 2020 年 9 月 27 日
  • 筆記

創建第一個flutter

編輯器: vscode

一、創建flutter項目

1.啟動vscode

2.按ctrl+shift+p打開命令面板

image-20200827111457149

3.輸入flutter 選擇Flutter: New Project

image-20200827111428312

4.輸入創建項目名稱

image-20200827111543034

5.指定存放項目地址。自動創建flutter基礎項目結構 顯示main.dart文件

image-20200827111623373

image-20200827111647155

二、運行項目

1.選擇運行設備

image-20200827111717327

2.按 F5 鍵或調用Debug>Start Debugging 運行項目

三、體驗熱重載

1.把lib/main.dart文件中 'You have pushed the button this many times:' 改為 'You have clicked the button this many times:'

image-20200827112108074

image-20200827112135241

2.調用保存自動熱更新

三、創建 Flutter app

1.替換 lib/main.dart 刪除lib / main.dart中的所有程式碼,然後替換為下面的程式碼,它將在螢幕的中心顯示「Hello World」.

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  
  1. 使用外部包(package) 打開pubspec.yaml文件添加 english_words到依賴列表

image-20200827112923036

3.添加後編輯器會自動拉取依賴

image-20200827113038939

4.在 lib/main.dart 中, 引入 english_words, 如高亮顯示的行所示:

image-20200827113206753

5.使用 English words 包生成文本來替換字元串「Hello World」.

image-20200827114209105

tips:果應用程式正在運行,請使用熱重載按鈕 (lightning bolt icon) 更新正在運行的應用程式。每次單擊熱重載或保存項目時,都會在正在運行的應用程式中隨機選擇不同的單詞對。 這是因為單詞對是在 build 方法內部生成的。每次MaterialApp需要渲染時或者在Flutter Inspector中切換平台時 build 都會運行.

四、添加有狀態的部件(Stateful widget)

  1. 添加有狀態的 RandomWords widget 到 main.dart。 它也可以在MyApp之外的文件的任何位置使用,但是本示例將它放到了文件的底部。RandomWords widget除了創建State類之外幾乎沒有其他任何東西

image-20200827115645926

  1. 添加 RandomWordsState 類.該應用程式的大部分程式碼都在該類中, 該類持有RandomWords widget的狀態。這個類將保存隨著用戶滾動而無限增長的生成的單詞對, 以及喜歡的單詞對,用戶通過重複點擊心形 ❤️ 圖標來將它們從列表中添加或刪除。

你會一步一步地建立這個類。首先,通過添加高亮顯示的程式碼創建一個最小類

image-20200827115723984

  1. 在添加狀態類後,IDE會提示該類缺少build方法。接下來,您將添加一個基本的build方法,該方法通過將生成單詞對的程式碼從MyApp移動到RandomWordsState來生成單詞對。

將build方法添加到RandomWordState中,如下面高亮程式碼所示

image-20200827115737112

  1. 通過下面高亮顯示的程式碼,將生成單詞對代的碼從MyApp移動到RandomWordsState中

image-20200827115752846

五、創建一個無限滾動listView

  1. 向RandomWordsState類中添加一個_suggestions列表以保存建議的單詞對。 該變數以下劃線(_)開頭,在Dart語言中使用下劃線前綴標識符,會強制其變成私有的。

另外,添加一個biggerFont變數來增大字體大小

class RandomWordsState extends State<RandomWords> {
  final _suggestions = <WordPair>[];

  final _biggerFont = const TextStyle(fontSize: 18.0);
  ...
}
  1. 向RandomWordsState類添加一個 _buildSuggestions() 函數. 此方法構建顯示建議單詞對的ListView。

ListView類提供了一個builder屬性,itemBuilder 值是一個匿名回調函數, 接受兩個參數- BuildContext和行迭代器i。迭代器從0開始, 每調用一次該函數,i就會自增1,對於每個建議的單詞對都會執行一次。該模型允許建議的單詞對列表在用戶滾動時無限增長。

添加如下高亮的行:

class RandomWordsState extends State<RandomWords> {
  ...
  Widget _buildSuggestions() {
    return new ListView.builder(
      padding: const EdgeInsets.all(16.0),
      // 對於每個建議的單詞對都會調用一次itemBuilder,然後將單詞對添加到ListTile行中
      // 在偶數行,該函數會為單詞對添加一個ListTile row.
      // 在奇數行,該函數會添加一個分割線widget,來分隔相鄰的詞對。
      // 注意,在小螢幕上,分割線看起來可能比較吃力。
      itemBuilder: (context, i) {
        // 在每一列之前,添加一個1像素高的分隔線widget
        if (i.isOdd) return new Divider();

        // 語法 "i ~/ 2" 表示i除以2,但返回值是整形(向下取整),比如i為:1, 2, 3, 4, 5
        // 時,結果為0, 1, 1, 2, 2, 這可以計算出ListView中減去分隔線後的實際單詞對數量
        final index = i ~/ 2;
        // 如果是建議列表中最後一個單詞對
        if (index >= _suggestions.length) {
          // ...接著再生成10個單詞對,然後添加到建議列表
          _suggestions.addAll(generateWordPairs().take(10));
        }
        return _buildRow(_suggestions[index]);
      }
    );
  }
}
  1. 對於每一個單詞對,_buildSuggestions函數都會調用一次_buildRow。 這個函數在ListTile中顯示每個新詞對,這使您在下一步中可以生成更漂亮的顯示行

在RandomWordsState中添加一個_buildRow函數 :

class RandomWordsState extends State<RandomWords> {
  ...

  Widget _buildRow(WordPair pair) {
    return new ListTile(
      title: new Text(
        pair.asPascalCase,
        style: _biggerFont,
      ),
    );
  }
}
  1. 更新RandomWordsState的build方法以使用_buildSuggestions(),而不是直接調用單詞生成庫。 更改後如下面高亮部分:

    class RandomWordsState extends State<RandomWords> {
      ...
      
  2. 更新MyApp的build方法。從MyApp中刪除Scaffold和AppBar實例。 這些將由RandomWordsState管理,這使得用戶在下一步中從一個螢幕導航到另一個螢幕時, 可以更輕鬆地更改導航欄中的的路由名稱。

用下面高亮部分替換最初的build方法:

class MyApp extends StatelessWidget {
  

六、添加交互

在這一步中,您將為每一行添加一個可點擊的心形 ❤️ 圖標。當用戶點擊列表中的條目,切換其「收藏」狀態時,將該詞對添加到或移除出「收藏夾」。

  1. 添加一個 _saved Set(集合) 到RandomWordsState。這個集合存儲用戶喜歡(收藏)的單詞對。 在這裡,Set比List更合適,因為Set中不允許重複的值。

    class RandomWordsState extends State<RandomWords> {
      final _suggestions = <WordPair>[];
    
      final _saved = new Set<WordPair>();
    
      final _biggerFont = const TextStyle(fontSize: 18.0);
      ...
    }
  2. 在 _buildRow 方法中添加 alreadySaved來檢查確保單詞對還沒有添加到收藏夾中。

    Widget _buildRow(WordPair pair) {
      final alreadySaved = _saved.contains(pair);
      ...
    }
  3. 同時在 _buildRow()中, 添加一個心形 ❤️ 圖標到 ListTiles以啟用收藏功能。接下來,你就可以給心形 ❤️ 圖標添加交互能力了。

添加下面高亮的行:

Widget _buildRow(WordPair pair) {
  final alreadySaved = _saved.contains(pair);
  return new ListTile(
    title: new Text(
      pair.asPascalCase,
      style: _biggerFont,
    ),
    trailing: new Icon(
      alreadySaved ? Icons.favorite : Icons.favorite_border,
      color: alreadySaved ? Colors.red : null,
    ),
  );
}
  1. 重新啟動應用。你現在可以在每一行看到心形❤️圖標️,但它們還沒有交互。
  2. 在 _buildRow中讓心形❤️圖標變得可以點擊。如果單詞條目已經添加到收藏夾中, 再次點擊它將其從收藏夾中刪除。當心形❤️圖標被點擊時,函數調用setState()通知框架狀態已經改變。

添加如下高亮的行:

Widget _buildRow(WordPair pair) {
  final alreadySaved = _saved.contains(pair);
  return new ListTile(
    title: new Text(
      pair.asPascalCase,
      style: _biggerFont,
    ),
    trailing: new Icon(
      alreadySaved ? Icons.favorite : Icons.favorite_border,
      color: alreadySaved ? Colors.red : null,
    ),
    onTap: () {
      setState(() {
        if (alreadySaved) {
          _saved.remove(pair);
        } else {
          _saved.add(pair);
        }
      });
    },
  );
}

提示: 在Flutter的響應式風格的框架中,調用setState() 會為State對象觸發build()方法,從而導致對UI的更新

七、導航到新頁面

在這一步中,您將添加一個顯示收藏夾內容的新頁面(在Flutter中稱為路由(route))。您將學習如何在主路由和新路由之間導航(切換頁面)。

在Flutter中,導航器管理應用程式的路由棧。將路由推入(push)到導航器的棧中,將會顯示更新為該路由頁面。 從導航器的棧中彈出(pop)路由,將顯示返回到前一個路由。

  1. 在RandomWordsState的build方法中為AppBar添加一個列表圖標。當用戶點擊列表圖標時,包含收藏夾的新路由頁面入棧顯示。

提示: 某些widget屬性需要單個widget(child),而其它一些屬性,如action,需要一組widgets(children),用方括弧[]表示。

將該圖標及其相應的操作添加到build方法中:

class RandomWordsState extends State<RandomWords> {
  ...
  
  1. 向RandomWordsState類添加一個 _pushSaved() 方法.

    class RandomWordsState extends State<RandomWords> {
      ...
      void _pushSaved() {
      }
    }

熱重載應用,列表圖標將會出現在導航欄中。現在點擊它不會有任何反應,因為 _pushSaved 函數還是空的。

  1. 當用戶點擊導航欄中的列表圖標時,建立一個路由並將其推入到導航管理器棧中。此操作會切換頁面以顯示新路由。

新頁面的內容在在MaterialPageRoute的builder屬性中構建,builder是一個匿名函數。

添加Navigator.push調用,這會使路由入棧(以後路由入棧均指推入到導航管理器的棧)

void _pushSaved() {
  Navigator.of(context).push(
  );
}
  1. 添加MaterialPageRoute及其builder。 現在,添加生成ListTile行的程式碼。ListTile的divideTiles()方法在每個ListTile之間添加1像素的分割線。 該 divided 變數持有最終的列表項。

    void _pushSaved() {
      Navigator.of(context).push(
        new MaterialPageRoute(
          builder: (context) {
            final tiles = _saved.map(
              (pair) {
                return new ListTile(
                  title: new Text(
                    pair.asPascalCase,
                    style: _biggerFont,
                  ),
                );
              },
            );
            final divided = ListTile
              .divideTiles(
                context: context,
                tiles: tiles,
              )
              .toList();
          },
        ),
      );
    }
  2. builder返回一個Scaffold,其中包含名為「Saved Suggestions」的新路由的應用欄。 新路由的body由包含ListTiles行的ListView組成; 每行之間通過一個分隔線分隔。

添加如下高亮的程式碼:

void _pushSaved() {
  Navigator.of(context).push(
    new MaterialPageRoute(
      builder: (context) {
        final tiles = _saved.map(
          (pair) {
            return new ListTile(
              title: new Text(
                pair.asPascalCase,
                style: _biggerFont,
              ),
            );
          },
        );
        final divided = ListTile
          .divideTiles(
            context: context,
            tiles: tiles,
          )
          .toList();

        return new Scaffold(
          appBar: new AppBar(
            title: new Text('Saved Suggestions'),
          ),
          body: new ListView(children: divided),
        );
      },
    ),
  );
}
  1. 熱重載應用程式。收藏一些選項,並點擊應用欄中的列表圖標,在新路由頁面中顯示收藏的內容。 請注意,導航器會在應用欄中添加一個「返回」按鈕。你不必顯式實現Navigator.pop。點擊後退按鈕返回到主頁路由。

七、使用主題更改UI

image-20200827142409850