要開始使用 Flutter,你需要對 Dart 程式語言(Flutter 應用程式是用 Dart 撰寫的)以及元件 (Widgets) 有一些基本認識。元件 (Widgets) 是 Flutter UI 的構建基礎。本頁將會介紹這兩個主題,但在本系列教學中你還會持續深入學習。頁面中也會列出額外的學習資源,但你無需成為這兩個主題的專家即可繼續學習。

元件 (Widgets)

#

在 Flutter 的相關討論中,你經常會聽到「一切皆元件 (Everything is a widget)」這句話。元件 (Widgets) 是 Flutter 應用程式使用者介面的構建基礎,每個元件 (Widget) 都是 UI 某一部分的不可變聲明。元件 (Widgets) 用來描述使用者介面的所有面向,從文字、按鈕等實體元素,到像是內距(padding)、對齊(alignment)等版面配置效果。

元件 (Widgets) 透過組合(composition)形成階層結構。每個元件 (Widget) 都嵌套於其父元件 (parent) 之內,並且可以從父元件接收 context。這種結構會一路延伸到根元件 (root widget),如下方這個簡單的例子所示:

dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp( // Root widget
      home: Scaffold(
        appBar: AppBar(
          title: const Text('My Home Page'),
        ),
        body: Center(
          child: Builder(
            builder: (context) {
              return Column(
                children: [
                  const Text('Hello, World!'),
                  const SizedBox(height: 20),
                  ElevatedButton(
                    onPressed: () {
                      print('Click!');
                    },
                    child: const Text('A button'),
                  ),
                ],
              );
            },
          ),
        ),
      ),
    );
  }
}

在前述程式碼中, 所有被實例化的類別都是元件(Widgets): MaterialAppScaffoldAppBarTextCenterBuilderColumnSizedBox,以及 ElevatedButton

元件組合(Widget composition)

#

如前所述,Flutter 強調以元件(Widget)作為組合的單位。元件通常是由許多其他小型、單一用途的元件所組成,這些元件結合起來可以產生強大的效果。

有一些版面配置元件(Layout widgets),例如 PaddingAlignmentRowColumnGrid。這些版面配置元件本身沒有視覺上的呈現。 它們唯一的目的就是 控制其他元件在版面上的某些層面。 Flutter 也包含了一些實用元件(utility widgets), 善用這種組合式設計。例如,Container 是一個常用的元件, 它是由多個負責版面配置、繪製、定位和尺寸調整的元件所組成。 有些元件具有視覺上的呈現, 像是前述範例中的 ElevatedButtonText,以及像 IconImage 這類元件。

如果你執行上述範例的程式碼, Flutter 會繪製一個按鈕,並在螢幕中央垂直排列顯示 「Hello, World!」這段文字。 為了排版這些元素,這裡有一個 Center 元件, 它會將其子元件置中於可用空間, 還有一個 Column 元件, 會將其子元件依序垂直排列。

A diagram that shows widget composition with a series of lines and nodes.

在本系列的下一頁, 你將會進一步學習 Flutter 中的版面配置。

建立元件(Building widgets)

#

要在 Flutter 中建立使用者介面, 你需要覆寫元件物件上的 build 方法。 所有元件都必須有一個 build 方法, 而且這個方法必須回傳另一個元件。例如, 如果你想在螢幕上加入帶有間距的文字, 你可以這樣撰寫:

dart
class PaddedText extends StatelessWidget {
  const PaddedText({super.key});

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: const Text('Hello, World!'),
    );
  }
}

當此 widget 被建立時,以及當此 widget 的相依項(例如傳遞進 widget 的狀態)發生變化時,框架會呼叫 build 方法。
這個方法有可能在每一個畫面(frame)都被呼叫,因此除了建立 widget 之外,不應有其他副作用。
若想進一步了解 Flutter 如何渲染 widgets,請參考 Flutter architectural overview

Widget 狀態

#

框架引入了兩大類 widget:有狀態(stateful)和無狀態(stateless)widgets。

沒有可變狀態(即其類別屬性不會隨時間改變)的 widgets 會繼承自 StatelessWidget
許多內建 widgets 都是無狀態的,例如 PaddingTextIcon
當你自行建立 widgets 時,大多數情況下會建立 Stateless 這類無狀態 widget。

另一方面,如果一個 widget 的獨特特性需要根據使用者互動或其他因素而改變,這個 widget 就是有狀態的(stateful)。
舉例來說,如果一個 widget 有一個計數器,每當使用者點擊按鈕時就會遞增,那麼這個計數器的值就是該 widget 的狀態(state)。
當這個值改變時,widget 需要被重新建構,以更新其在 UI 上的部分。
這類 widgets 會繼承自 StatefulWidget,而(因為 widget 本身是不可變的)可變狀態會存放在另一個繼承自 State 的類別中。

StatefulWidgets 沒有 build 方法;相反地,它們的使用者介面是透過其 State 物件來建構,如下方範例所示。

dart
class CounterWidget extends StatefulWidget {
  @override
  State<CounterWidget> createState() => _CounterWidgetState();
}

class _CounterWidgetState extends State<CounterWidget> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }
  
  @override
  Widget build(BuildContext context) {
    return Text('$_counter');
  }
}

每當你對 State 物件進行變更 (例如,遞增計數器), 你必須呼叫 setState 來通知框架 更新使用者介面, 這會再次呼叫 Statebuild 方法。

將狀態與元件(Widget)物件分離, 讓其他元件可以用完全相同的方式 處理無狀態元件(stateless widgets)和有狀態元件, 而不必擔心狀態遺失。 父元件不需要保留子元件來維持其狀態, 可以隨時建立子元件的新實例, 而不會遺失子元件的持久狀態。 框架會自動處理尋找及 在適當時機重複利用現有狀態物件的工作。

關於 StatefulWidget 物件的更多資訊, 會在本系列稍後的 狀態管理課程 中介紹。

重要的元件(Widgets)

#

Flutter SDK(Flutter 軟體開發套件)內建了許多元件, 從最小的 UI 元素,如 Text, 到版面配置元件(Layout widgets),以及用於美化 應用程式的元件。以下這些元件 是你在學習路徑的下一課中 最需要認識的:

元件預覽工具

#

你可以即時預覽你的元件渲染效果,無需執行完整應用程式。 想了解更多,請參考 Flutter Widget Previewer 指南。

下一步:版面配置(Layouts)

#

本頁介紹了 Flutter 的基礎概念,例如元件(Widgets), 並協助你熟悉閱讀 Flutter 與 Dart 程式碼。 如果你對於本頁遇到的每個主題還不完全清楚也沒關係, 因為接下來的每一頁都會針對特定主題深入說明。 在下一節,你將開始建立更有趣的 UI, 透過在 Flutter 中打造更複雜的版面配置。

如果你想練習本頁學到的內容, 可以閱讀 Building user interfaces with Flutter

意見回饋

#

由於本網站區塊仍在持續演進中, 我們歡迎你的意見回饋