跳至主要內容

Widgets

若要開始使用 Flutter,您需要熟悉 Dart 程式語言,Flutter 應用程式就是以這種語言編寫的,以及 Widget,Widget 是 Flutter UI 的基礎建構區塊。此頁面將介紹這兩者,但您將在此系列中繼續學習它們。此頁面中列出了其他資源,但您不必成為這兩個主題的專家即可繼續。

Widgets

#

關於 Flutter,您經常會聽到「一切皆為 Widget」。Widget 是 Flutter 應用程式使用者介面的建構區塊,每個 Widget 都是使用者介面一部分的不可變宣告。Widget 用於描述使用者介面的所有方面,包括文字和按鈕等實體方面,以及邊距和對齊方式等配置效果。

Widget 基於組成形成一個層次結構。每個 Widget 巢狀於其父 Widget 內,並可以接收來自父 Widget 的上下文。此結構一直延伸到根 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'),
                  ),
                ],
              );
            },
          ),
        ),
      ),
    );
  }
}

在上述程式碼中,所有實例化的類別都是 Widget:MaterialAppScaffoldAppBarTextCenterBuilderColumnSizedBoxElevatedButton

Widget 組成

#

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

有版面配置 Widget,例如 PaddingAlignmentRowColumnGrid。這些版面配置 Widget 本身沒有視覺表示。相反地,它們的唯一目的是控制另一個 Widget 版面配置的某些方面。Flutter 還包括利用此組成方法的實用 Widget。例如,Container 是一個常用的 Widget,它由多個負責版面配置、繪製、定位和調整大小的 Widget 組成。有些 Widget 具有視覺表示,例如前面範例中的 ElevatedButtonText,以及 IconImage 之類的 Widget。

如果您執行前面範例中的程式碼,Flutter 會繪製一個帶有文字「Hello, World!」的按鈕,該按鈕位於螢幕中央,並垂直配置。若要定位這些元素,會有一個 Center Widget,它將其子項定位在可用空間的中央,以及一個 Column Widget,它將其子項一個接一個地垂直配置。

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

在本系列的下一頁中,您將深入了解 Flutter 中的版面配置。

建立 Widget

#

若要在 Flutter 中建立使用者介面,您需要覆寫 Widget 物件上的 build 方法。所有 Widget 都必須具有 build 方法,而且必須傳回另一個 Widget。例如,如果您想在螢幕上新增帶有一些邊距的文字,您可以這樣寫

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 方法。此方法可能會在每個影格中呼叫,而且除了建立 Widget 之外不應有任何副作用。若要深入了解 Flutter 如何呈現 Widget,請查看Flutter 架構概述

Widget 狀態

#

框架引入了兩個主要類別的 Widget:有狀態和無狀態 Widget。

沒有可變狀態的 Widget(它們沒有隨時間變更的類別屬性)會繼承 StatelessWidget。許多內建 Widget 都是無狀態的,例如 PaddingTextIcon。當您建立自己的 Widget 時,您大部分時間都會建立 Stateless Widget。

另一方面,如果 Widget 的獨特特性需要根據使用者互動或其他因素而變更,則該 Widget 就是有狀態的。例如,如果 Widget 有一個計數器,每當使用者點擊按鈕時,計數器就會遞增,那麼計數器的值就是該 Widget 的狀態。當該值變更時,需要重新建立 Widget,以更新其 UI 的一部分。這些 Widget 會繼承 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 物件分離,可讓其他 Widget 以完全相同的方式處理無狀態和有狀態 Widget,而無需擔心狀態遺失。父項可以隨時建立子項的新執行個體,而不會遺失子項的持續狀態,而不需要保留子項來保留其狀態。框架會在適當時執行尋找和重複使用現有狀態物件的所有工作。

本系列稍後會提供更多關於 StatefulWidget 物件的資訊,請參閱狀態管理課程

需要了解的重要 Widget

#

Flutter SDK 包含許多內建 Widget,從最小的 UI 片段(例如 Text)到版面配置 Widget,以及設定應用程式樣式的 Widget。在您進入學習路徑中的下一課時,請務必注意以下 Widget。

下一步:版面配置

#

此頁面簡介了 Flutter 的基礎概念,例如 Widget,並可協助您熟悉閱讀 Flutter 和 Dart 程式碼。如果您對遇到的每個主題都不是很清楚,也沒關係,因為之後的每個頁面都會深入探討特定主題。在下一節中,您將開始透過在 Flutter 中建立更複雜的版面配置來建立更有趣的 UI。

如果您想練習在此頁面中學到的資訊,您可以閱讀使用 Flutter 建立使用者介面

意見回饋

#

由於網站的此部分仍在發展中,我們歡迎您提供意見回饋