五個你所不知道的Flutter開發細節

韜( ̄▽ ̄)發表於2018-10-14

一、利用IDE高效組合Widget

在Flutter中,UI的構建是通過Widget的層層巢狀實現的,開發過程中不可避免地需要頻繁修改Widget樹,從中插入或者移除一些Widget。

除了手動寫程式碼和剪下貼上去修改Widget樹之外,在Android Studio和Visual Studio Code中,你還有更高效的方法可以使用:

  • 在Android Studio中

Android Studio

  • 在Visual Studio Code中

Visual Studio Code

二、理解下劃線開頭命名的含義

Flutter所使用的Dart語言,沒有類似Java的publice protect private,以_開頭的變數、函式和類,意味著它僅在庫中是可視的

Libraries not only provide APIs, but are a unit of privacy: identifiers that start with an underscore (_) are visible only inside the library.出處

觀察以下幾個例子,加深理解:

  • 變數

五個你所不知道的Flutter開發細節
name變數以_開頭後,雖然都是繼承於Fruit,但是由於Apple不在同一庫中,因此它無法訪問父類的name屬性。

  • 函式

五個你所不知道的Flutter開發細節
getName方法以_開頭後,雖然都是繼承於Fruit,但是由於Apple不在同一庫中,因此它無法訪問父類的getName方法,也無須實現它。

五個你所不知道的Flutter開發細節
Banana類可以訪問在同一個庫中的_Fruit類,但是由於Apple不在同一庫中,因此它無法訪問_Fruit類。

三、區別final與const

在Dart中,當你不需要去改變一個變數的時候,應該使用final或者const,而不是使用var去宣告一個變數。

一個final變數只允許被賦值一次,必須在定義時或者建構函式參數列中將其初始化。

const所修飾的是編譯時常量,我們在編譯時就已經知道了它的值,它的值是不可改變的。

它們的區別就在於,const比final更加嚴格,看以下幾個例子:

final List<String> list = [];
list.add('1'); // 正確

const List<String> list = [];
list.add('1'); // 錯誤,執行時報錯:Cannot add to an unmodifiable list
複製程式碼
final timestamp = new DateTime.now().millisecondsSinceEpoch; // 正確

const timestamp = new DateTime.now().millisecondsSinceEpoch; 
// 錯誤,編譯前報錯:Const variables must be initialized with a constant value
複製程式碼

官方文件

四、使用Debug Painting除錯介面

Flutter提供的Debug Painting可以很方便地協助我們觀察介面的佈局,除錯介面的開發

五個你所不知道的Flutter開發細節
在Android Studio和Visual Studio Code中都有提供開關去顯示或隱藏Debug Painting(前提是App處於除錯執行狀態):

  • 在Android Studio中

Android Studio

  • 在Visual Studio Code中

Visual Studio Code

五、使用FocusScope轉移焦點,隱藏輸入法

我們在開發App的時候,會經常遇到當點選空白區域時將輸入法隱藏的需求。一想到輸入法,大家可能都會想通過Method Channle,讓原生實現隱藏輸入法的辦法來解決。其實我們可以通過FocusScope來轉移焦點,同樣能夠達到隱藏輸入法的目的。

五個你所不知道的Flutter開發細節

Container(
        height: 500.0,
        child: new GestureDetector(
          onTap: () {
            // 通過GestureDetector捕獲點選事件,再通過FocusScope將焦點轉移至空焦點——new FocusNode()
            FocusScope.of(context).requestFocus(FocusNode());
          },
          child: Container(
              margin: EdgeInsets.all(30.0),
              child: ListView(children: <Widget>[
                TextField(
                  decoration: InputDecoration(labelText: 'Username'),
                ),
                TextField(
                  decoration: InputDecoration(labelText: 'Password'),
                )
              ])),
        ),
      ),
複製程式碼

開發過程中還發現了Flutter一個bug,這裡傳遞給FocusScope的context不能在MaterialApp下面,即你需要將這部分程式碼放到獨立的一個Widget裡面。 具體參考這個issue最後一個評論。

相關文章