天天看點

Flutter之基礎Widget

在前面搭好環境後以及快速了解的dart的文法後,開始學習Flutter的基礎Widget!!

目錄

Flutter Widget庫介紹

Widget

StatelessWidget

StatefulWidget

State

State生命周期

Text

使用字型

在asset中聲明

使用字型

Package中的字型

按鈕

自定義按鈕外觀

圖檔

ImageProvider

從asset中加載圖檔

  從網絡加載圖檔

TextField

在Flutter中大部分類皆繼承Widget,Widget的功能是“描述一個UI元素的配置資料”,它就是說,Widget其實并不是表示最終繪制在裝置螢幕上的顯示元素,而隻是顯示元素的一個配置資料。實際上,Flutter中真正代表螢幕上顯示元素的類是

Element

,也就是說Widget隻是描述

Element

的一個配置。

Flutter Widget庫介紹

Flutter提供了一套豐富、強大的基礎widget,在基礎widget庫之上Flutter又提供了一套Material風格(Android預設的視覺風格)和一套Cupertino風格(iOS視覺風格)的widget庫。要使用基礎widget庫,需要先導入:

// Android
import 'package:flutter/widgets.dart';

// iOS
import 'package:flutter/cupertino.dart';
           

Widget

下面是Widget類的源代碼:

abstract class Widget extends DiagnosticableTree {
  /// Initializes [key] for subclasses.
  const Widget({ this.key });
   
  final Key key;

  @protected
  Element createElement();

  @override
  String toStringShort() {
    return key == null ? '$runtimeType' : '$runtimeType-$key';
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;
  }

  static bool canUpdate(Widget oldWidget, Widget newWidget) {
    return oldWidget.runtimeType == newWidget.runtimeType
        && oldWidget.key == newWidget.key;
  }
}
           
  • 類Key:目前Widget的唯一标示符,決定Widget是否複用。在canUpdate方法中判斷。
  • 方法createElement:建立顯示的對象。

StatelessWidget

StatelessWidget用于不需要維護狀态的場景,它通常在

build

方法中通過嵌套其它Widget來建構UI,在建構過程中會遞歸的建構其嵌套的Widget

StatefulWidget

abstract class StatefulWidget extends Widget {
  const StatefulWidget({ Key key }) : super(key: key);

  @override
  StatefulElement createElement() => new StatefulElement(this);

  @protected
  State createState();
}
           
  • StatefulElement

     間接繼承自

    Element

    類,與StatefulWidget相對應(作為其配置資料)。

    StatefulElement

    中可能會多次調用

    createState()

    來建立狀态(State)對象。
  • createState()

     用于建立和Stateful widget相關的狀态,它在Stateful widget的生命周期中可能會被多次調用。例如,當一個Stateful widget同時插入到widget樹的多個位置時,Flutter framework就會調用該方法為每一個位置生成一個獨立的State執行個體,其實,本質上就是一個

    StatefulElement

    對應一個State執行個體。

State

一個StatefulWidget類會對應一個State類,State表示與其對應的StatefulWidget要維護的狀态,State中的儲存的狀态資訊可以:

  1. 在widget build時可以被同步讀取。
  2. 在widget生命周期中可以被改變,當State被改變時,可以手動調用其

    setState()

    方法通知Flutter framework狀态發生改變,Flutter framework在收到消息後,會重新調用其

    build

    方法重新建構widget樹,進而達到更新UI的目的

State生命周期

// 初始化狀态,隻執行一次
 void initState() { }

 // 當widget依賴的對象發生變化時調用,例如全局的主題或語言
 void didChangeDependencies() { }

 // 當widget重新建構時調用,根據canUpdate方法判斷
 void didUpdateWidget(covariant T oldWidget) { }

 // 建構UI
 void build() { }

 // 調試模式下,熱重載執行,Release模式不會執行
 void reassemble() { }
  
 // 當widget被移除時調用
 void deactivate() { }

 // 當widget被永久移除時,可以做釋放資源
 void dispose() { }
           

 widget被加載顯示的時候會依次調用initState,didChangeDependencies,build等方法。

 點選熱重載時會依次調用reassemble,didUpdateWidget,build等方法。

 發生界面切換時會依次調用deactivate,dispose等方法。

Text

顯示文本,其一些樣式屬性和Android的TextView類似,比如,文本對齊方式,大小,顔色等等。

使用字型

在Flutter中使用字型分兩步完成。首先在

pubspec.yaml

中聲明它們,以確定它們會打包到應用程式中。然後通過

TextStyle

屬性使用字型。

在asset中聲明

要将字型打檔案打包到應用中,和使用其它資源一樣,要先在

pubspec.yaml

中聲明它。然後将字型檔案複制到在

pubspec.yaml

中指定的位置。如

flutter:
  fonts:
    - family: Raleway
      fonts:
        - asset: assets/fonts/Raleway-Regular.ttf
        - asset: assets/fonts/Raleway-Medium.ttf
          weight: 500
        - asset: assets/fonts/Raleway-SemiBold.ttf
          weight: 600
    - family: AbrilFatface
      fonts:
        - asset: assets/fonts/abrilfatface/AbrilFatface-Regular.ttf
           

使用字型

// 聲明文本樣式
const textStyle = const TextStyle(
  fontFamily: 'Raleway',
);

// 使用文本樣式
var buttonText = const Text(
  "Use the font for this text",
  style: textStyle,
);
           

Package中的字型

要使用Package中定義的字型,必須提供

package

參數。例如,假設上面的字型聲明位于

my_package

包中。然後建立TextStyle的過程如下

const textStyle = const TextStyle(
  fontFamily: 'Raleway',
  package: 'my_package', //指定包名
);
           

如果在package包内部使用它自己定義的字型,也應該在建立文本樣式時指定

package

參數,如上例所示。

一個包也可以隻提供字型檔案而不需要在pubspec.yaml中聲明。 這些檔案應該存放在包的

lib/

檔案夾中。字型檔案不會自動綁定到應用程式中,應用程式可以在聲明字型時有選擇地使用這些字型。假設一個名為my_package的包中有一個字型檔案:

lib/fonts/Raleway-Medium.ttf
           

然後,應用程式可以聲明一個字型,如下面的示例所示:

flutter:
   fonts:
     - family: Raleway
       fonts:
         - asset: assets/fonts/Raleway-Regular.ttf
         - asset: packages/my_package/fonts/Raleway-Medium.ttf
           weight: 500
           

lib/

是隐含的,是以它不應該包含在asset路徑中。

在這種情況下,由于應用程式本地定義了字型,是以在建立TextStyle時可以不指定

package

參數:

const textStyle = const TextStyle(
  fontFamily: 'Raleway',
);
           

按鈕

Material widget庫中提供了多種按鈕Widget如RaisedButton、FlatButton、OutlineButton等,它們都是直接或間接對RawMaterialButton的包裝定制,是以他們大多數屬性都和

RawMaterialButton

一樣。在介紹各個按鈕時我們先介紹其預設外觀,而按鈕的外觀大都可以通過屬性來自定義,我們在後面統一介紹這些屬性。另外,所有Material 庫中的按鈕都有如下相同點:

  1. 按下時都會有“水波動畫”。
  2. 有一個

    onPressed

    屬性來設定點選回調,當按鈕按下時會執行該回調,如果不提供該回調則按鈕會處于禁用狀态,禁用狀态不響應使用者點選。

有這幾種:RaisedButton,FlatButton,OutlineButton,IconButton 具體使用可檢視Flutter Gallery Demo。

自定義按鈕外觀

const FlatButton({
  ...  
  @required this.onPressed, //按鈕點選回調
  this.textColor, //按鈕文字顔色
  this.disabledTextColor, //按鈕禁用時的文字顔色
  this.color, //按鈕背景顔色
  this.disabledColor,//按鈕禁用時的背景顔色
  this.highlightColor, //按鈕按下時的背景顔色
  this.splashColor, //點選時,水波動畫中水波的顔色
  this.colorBrightness,//按鈕主題,預設是淺色主題 
  this.padding, //按鈕的填充
  this.shape, //外形
  @required this.child, //按鈕的内容
})
           

圖檔

Flutter中,我們可以通過Image來加載并顯示圖檔,Image的資料源可以是asset、檔案、記憶體以及網絡。

ImageProvider

ImageProvider

 是一個抽象類,主要定義了圖檔資料擷取的接口

load()

,從不同的資料源擷取圖檔需要實作不同的

ImageProvider

 ,如

AssetImage

是實作了從Asset中加載圖檔的ImageProvider,而

NetworkImage

實作了從網絡加載圖檔的ImageProvider。

從asset中加載圖檔

  1. 在工程根目錄下建立一個

    images目錄

    ,并将圖檔avatar.png拷貝到該目錄。
  2. pubspec.yml

    中的

    flutter

    部分添加如下内容:
    assets:
      - images/avatar.png
               
  3. 加載圖檔
Image(
  image: AssetImage("images/avatar.png"),
  width: 100.0
);
           

Image也提供了一個快捷的構造函數

Image.asset

用于從asset中加載、顯示圖檔:

Image.asset("images/avatar.png",
  width: 100.0,
)
           

  從網絡加載圖檔

Image(
  image: NetworkImage(
      "https://avatars2.githubusercontent.com/u/20411648?s=460&v=4"),
  width: 100.0,
)
           

Image也提供了一個快捷的構造函數

Image.network

用于從網絡加載、顯示圖檔:

Image.network(
  "https://avatars2.githubusercontent.com/u/20411648?s=460&v=4",
  width: 100.0,
)
           

TextField

TextField用于文本輸入,它提供了很多屬性。

const TextField({
  ...
  TextEditingController controller, 
  FocusNode focusNode,
  InputDecoration decoration = const InputDecoration(),
  TextInputType keyboardType,
  TextInputAction textInputAction,
  TextStyle style,
  TextAlign textAlign = TextAlign.start,
  bool autofocus = false,
  bool obscureText = false,
  int maxLines = 1,
  int maxLength,
  bool maxLengthEnforced = true,
  ValueChanged<String> onChanged,
  VoidCallback onEditingComplete,
  ValueChanged<String> onSubmitted,
  List<TextInputFormatter> inputFormatters,
  bool enabled,
  this.cursorWidth = 2.0,
  this.cursorRadius,
  this.cursorColor,
  ...
})
           
  • controller:編輯框的控制器,通過它可以設定/擷取編輯框的内容、選擇編輯内容、監聽編輯文本改變事件。大多數情況下我們都需要顯式提供一個controller來與文本框互動。如果沒有提供controller,則TextField内部會自動建立一個。
  • focusNode:用于控制TextField是否占有目前鍵盤的輸入焦點。它是我們和鍵盤互動的一個handle。
  • InputDecoration:用于控制TextField的外觀顯示,如提示文本、背景顔色、邊框等。
  • keyboardType:用于設定該輸入框預設的鍵盤輸入類型,取值如下:

    | TextInputType枚舉值 | 含義 | | ------------------- | --------------------------------------------------- | | text | 文本輸入鍵盤 | | multiline | 多行文本,需和maxLines配合使用(設為null或大于1) | | number | 數字;會彈出數字鍵盤 | | phone | 優化後的電話号碼輸入鍵盤;會彈出數字鍵盤并顯示"* #" | | datetime | 優化後的日期輸入鍵盤;Android上會顯示“: -” | | emailAddress | 優化後的電子郵件位址;會顯示“@ .” | | url | 優化後的url輸入鍵盤; 會顯示“/ .” |

  • textInputAction:鍵盤動作按鈕圖示(即Enter鍵位圖示),它是一個枚舉值,有多個可選值,全部的取值清單讀者可以檢視API文檔
  • style:正在編輯的文本樣式。
  • textAlign: 輸入框内編輯文本在水準方向的對齊方式。
  • autofocus: 是否自動擷取焦點。
  • obscureText:是否隐藏正在編輯的文本,如用于輸入密碼的場景等,文本内容會用“•”替換。
  • maxLines:輸入框的最大行數,預設為1;如果為

    null

    ,則無行數限制。
  • maxLength和maxLengthEnforced :maxLength代表輸入框文本的最大長度,設定後輸入框右下角會顯示輸入的文本計數。maxLengthEnforced決定當輸入文本長度超過maxLength時是否阻止輸入,為true時會阻止輸入,為false時不會阻止輸入但輸入框會變紅。
  • onChange:輸入框内容改變時的回調函數;注:内容改變事件也可以通過controller來監聽。
  • onEditingComplete和onSubmitted:這兩個回調都是在輸入框輸入完成時觸發,比如按了鍵盤的完成鍵(對号圖示)或搜尋鍵(?圖示)。不同的是兩個回調簽名不同,onSubmitted回調是

    ValueChanged<String>

    類型,它接收目前輸入内容做為參數,而onEditingComplete不接收參數。
  • inputFormatters:用于指定輸入格式;當使用者輸入内容改變時,會根據指定的格式來校驗。
  • enable:如果為

    false

    ,則輸入框會被禁用,禁用狀态不接收輸入和事件,同時顯示禁用态樣式(在其decoration中定義)。
  • cursorWidth、cursorRadius和cursorColor:這三個屬性是用于自定義輸入框光标寬度、圓角和顔色的。

參考Flutter中文網