Flutter Widgets — 什么是 widget 树和 build

作者: IT Sectr 发布日期: 2026-02-21 阅读时间: 8 分钟

Flutter Widgets —— Google Flutter 框架中用户界面的基本构建块,该框架于 2018 年 12 月发布了稳定版本 1.0。在 Flutter 中,一切都是 widget:从屏幕和按钮到间距和对齐。Widgets 构成一棵树(widget tree),Flutter 在其自己的 Skia/Impeller 引擎上渲染这棵树,绕过平台的原生组件。根据 Google I/O (2025) 的数据,Flutter 被用于 Google Play 和 App Store 中的 50 多万个应用程序。Flutter 架构将 widgets 分为 StatelessWidget(不可变)和 StatefulWidget(通过 State 对象具有可变状态)。

要点

  • Flutter Widgets —— Flutter 中所有 UI 元素:从屏幕和按钮到间距和对齐;框架不使用平台的原生组件。
  • StatelessWidget —— 没有可变状态的 widget;显示通过构造函数传递的数据,并且在构建 (build) 后不会改变。
  • StatefulWidget —— 具有可变状态的 widget,状态存储在单独的 State 对象中,该对象在重建 (rebuild) 后仍然存在。
  • Widget 树 (widget tree) —— 描述 UI 的 widget 层次结构;Flutter 将其转换为 Element Tree 和 Render Tree 进行渲染。
  • BuildContext —— 构建上下文,提供对 widget 在树中位置、主题、MediaQuery 和 InheritedWidget 的访问。

什么是 Flutter Widgets?

Flutter Widgets —— Flutter 框架中所有 UI 元素,实现为不可变的 (immutable) Dart 类。Widget 是 UI 元素的配置:其大小、颜色、位置、事件处理。与 Android (XML + View) 或 iOS (Storyboard + UIView) 不同,Flutter 不使用原生组件 —— 一切由 Skia (Android/iOS/Linux) 或 Impeller (iOS/macOS) 引擎在 Canvas 上绘制。这确保了在所有平台上具有相同的外观,没有平台差异。Flutter 附带两套 widgets:Material Widgets(适用于 Android/Web 的 Google Material Design 3 设计)和 Cupertino Widgets(适用于 iOS/macOS 的 Apple HIG 设计)。开发人员可以在一个应用程序中组合这两套 widgets。每个 widget 都有一个 build() 方法,该方法返回一个子 widget 或它们的组合 —— 这就是构建 widget 树的方式。

Flutter 的三棵树

Flutter 使用三棵树运行:Widget Tree(配置,由开发人员创建)、Element Tree(将 widget 与树中的位置匹配,由框架管理)、Render Tree(计算布局和执行绘制的对象)。Widget 创建 Element,Element 创建 RenderObject。Element 在配置更改 (rebuild) 时被复用 —— 这是 Flutter 的优化机制:如果 widget 类型和 key 匹配,则不重新创建 Element,而是更新新配置。理解这三棵树是优化 Flutter 应用程序性能的关键。

StatelessWidget:不可变的 widgets

StatelessWidget —— 不存储内部状态的 widget。它通过构造函数接收参数,并在构建后无法更改。StatelessWidget 非常适合静态元素:标题、图标、头像、具有固定数据的列表。build() 方法在创建时和父 widget 更改时调用一次。由于 StatelessWidget 没有状态,它不需要单独的 State 对象 —— build() 直接在 widget 类中定义。

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

class ProfileHeader extends StatelessWidget {
  final String name;
  final String avatarUrl;

  const ProfileHeader({super.key, required this.name, required this.avatarUrl});

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        CircleAvatar(
          radius: 24,
          backgroundImage: NetworkImage(avatarUrl),
        ),
        const SizedBox(width: 12),
        Text(
          name,
          style: const TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.bold,
          ),
        ),
      ],
    );
  }
}

ProfileHeader —— 通过构造函数接收 name 和 avatarUrl 的 StatelessWidget。CircleAvatar 显示头像,Text 显示名称。Widget 在创建后无法更改这些值。使用 const 构造函数 (const ProfileHeader) 允许 Flutter 在父级重建时复用 widget 实例 —— 这是推荐用于所有 StatelessWidget 的微优化。

StatefulWidget:具有状态的 widgets

StatefulWidget —— 具有可变状态的 widget,存储在单独的 State 对象中。StatefulWidget 本身像 StatelessWidget 一样是不可变的。可变部分被提取到 State 中:State —— 创建一个对象,该对象在 widget 的多次重建中仍然存在。当状态更改时 (setState()),Flutter 调用 State 的 build(),更新 UI。StatefulWidget 用于交互式元素:计数器、文本字段、复选框、动画、定时器。

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

class LikeButton extends StatefulWidget {
  const LikeButton({super.key});

  @override
  State<LikeButton> createState() => _LikeButtonState();
}

class _LikeButtonState extends State<LikeButton> {
  bool liked = false;
  int count = 42;

  void _toggleLike() {
    setState(() {
      liked = !liked;
      count += liked ? 1 : -1;
    });
  }

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: _toggleLike,
      child: Text(liked ? '♥ $count' : '♡ $count'),
    );
  }
}

LikeButton —— 带有 State 类 _LikeButtonState 的 StatefulWidget。liked 和 count 字段是存储在 State 中的状态,在重建时不会重置。setState() 通知 Flutter 需要重建 UI。Flutter 不会在每次父级重建时重新创建 State —— 仅在配置更改时(key 或 widget 类型)。在 IT Sectr,我们使用 StatelessWidget 进行显示,使用 StatefulWidget 进行交互式组件,遵循将 StatefulWidget 最小化到变更边界的原则。

Widget 树:从 Widget 到 RenderObject

Widget Tree —— 描述应用程序 UI 的 widget 层次结构。Flutter 将 Widget Tree 转换为 Element Tree:每个 Widget 创建一个 Element,跟踪其在树中的位置以及与 RenderObject 的连接。Render Tree 执行布局(确定大小和位置)和绘制。Element 是关键优化层:如果 widget 类型和 key 在重建时没有更改,则 Element 被复用,更新配置而无需重新创建 RenderObject。这确保了 Flutter 在高帧率 (60/120 FPS) 下的性能。

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

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Flutter Widgets')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.flutter_dash, size: 80),
            const SizedBox(height: 16),
            const Text(
              '你好,Flutter!',
              style: TextStyle(fontSize: 24),
            ),
          ],
        ),
      ),
    );
  }
}

HomeScreen 的 widget 树:Scaffold → AppBar + Center → Column → [Icon, SizedBox, Text]。Scaffold —— Material Design 的主要布局 widget。Center 居中子 Column。Column 垂直排列子元素,居中对齐 (mainAxisAlignment.center)。Flutter 从上到下计算布局(约束从父级传递),从下到上计算大小(sizedByParent 或 sizing from children)。

BuildContext:构建上下文和对树的访问

BuildContext —— widget 在 Element Tree 中位置的描述符。每个 build() 方法都接收 BuildContext,通过它 widget 可以访问:MediaQuery(屏幕大小、方向、像素密度、安全区域)、Theme (MaterialThemeData 或 CupertinoThemeData)、Navigator(导航栈)、ScaffoldMessenger (SnackBar)、InheritedWidget(沿树向下传递数据)。BuildContext 不应在 build() 完成后存储或在同步上下文之外使用 —— 这会导致诸如 "Scaffold.of() called with a context that does not contain a Scaffold" 的错误。与其存储 context,不如使用 Builder widget 或 InheritedWidget 模式来访问数据。

Key:在树中标识 widget

Key —— 每个 widget 构造函数的可选参数 (super.key)。Key 帮助 Flutter 在列表中元素顺序/数量更改时标识 widget。没有 key,Flutter 根据类型和位置比较 widget;在不使用 key 的情况下向列表中间添加元素时,Flutter 为错误的 widget 复用 Element,导致状态 (StatefulWidget) 和动画错误。对于列表使用 ValueKey(唯一标识符)、ObjectKey(基于数据对象)、UniqueKey(每次重建保证唯一 —— 用于强制重新创建)。

Flutter widget 目录:Material、Cupertino、Layout

Flutter SDK(稳定版本 3.3+、Dart 3+)包含 200 多个内置 widget,分为以下几类:Layout (Row, Column, Stack, Container, Expanded, Flexible, Wrap, GridView, ListView, CustomScrollView)、Material Design (Scaffold, AppBar, Card, Drawer, BottomNavigationBar, FloatingActionButton, TabBar, Chip, DataTable)、Cupertino (CupertinoPageScaffold, CupertinoNavigationBar, CupertinoButton, CupertinoTabBar)、Painting & Effects (Opacity, DecoratedBox, ClipRect, Transform, BackdropFilter, ShaderMask)、Async (FutureBuilder, StreamBuilder) 和 Accessibility (Semantics, MergeSemantics, ExcludeSemantics)。Layout widget 是每个 Flutter UI 的基础:Row 用于水平序列、Column 用于垂直序列、Stack 用于重叠元素、Container 与 BoxDecoration 用于装饰。

类别关键 widgets用途
LayoutRow, Column, Stack, Container, Expanded, Flexible子元素的位置和大小
MaterialScaffold, AppBar, Card, Drawer, FAB, TabBarMaterial Design 3 UI 组件
CupertinoCupertinoPageScaffold, CupertinoNavigationBar, CupertinoButtoniOS 风格的组件
PaintingOpacity, ClipRect, Transform, DecoratedBox, BackdropFilter视觉效果和裁剪
AsyncFutureBuilder, StreamBuilder带 UI 状态的异步数据加载
AccessibilitySemantics, MergeSemantics为屏幕阅读器进行语义标记

常见问题

StatelessWidget 和 StatefulWidget 有什么区别?

StatelessWidget 没有内部状态 —— 所有数据通过构造函数传递且不会改变。StatefulWidget 将可变状态存储在单独的 State 对象中,该对象在重建后仍然存在。状态更改调用 setState(),Flutter 重建 UI。对于不可变元素使用 StatelessWidget;对于交互式元素使用 StatefulWidget。

Flutter 中的 BuildContext 是什么?

BuildContext —— widget 在 Element Tree 中位置的描述符,传递给 build() 方法。通过 context,widget 可以访问 MediaQuery、Theme、Navigator、ScaffoldMessenger 和 InheritedWidget。BuildContext 不应在 build() 完成后存储。对于数据访问,使用 Builder widget 或 InheritedWidget。

使用 Flutter 需要了解 Dart 吗?

是的,Flutter 使用 Dart 作为唯一的编程语言。Dart 是一种静态类型语言,具有 null-safety、sound types、extension methods 和 pattern matching。开始时,Dart 的基础知识就足够了:类、函数、async/await、集合。Dart 通过 Dart Native 编译为本机代码 (AOT),通过 Dart2JS 编译为 JavaScript(用于 Web)。

Flutter 仅适用于移动平台吗?

不,Flutter 支持六个平台:iOS、Android、Web、macOS、Windows、Linux。超过 90% 的代码对所有平台都是通用的。平台适配(相机、文件系统)通过插件或平台通道实现。对于桌面,Flutter 使用 Flutter Desktop 窗口封装器;对于 Web,使用 CanvasKit (WebGL) 引擎或 HTML 渲染器。

Flutter 如何确保 60 FPS 的性能?

Flutter 实现 60/120 FPS 归功于:自己的 2D 引擎 (Skia/Impeller)、没有原生 bridge(不像 React Native)、三棵树 (Widget → Element → Render) 在类型/key 不变时复用 Element、单向传递的布局算法 (constraints down, sizes up) 以及 RepaintBoundary 用于隔离各个屏幕区域的重新绘制。

总结

  • Flutter Widgets —— 所有 UI 元素:从 Scaffold 到 SizedBox;Flutter 自己在 Skia/Impeller 上绘制它们,不使用原生组件。
  • StatelessWidget —— 无状态 widget;build() 基于构造函数的不变参数返回 UI。
  • StatefulWidget —— State 中具有可变状态的 widget;setState() 触发 UI 重建。
  • 三棵树 Flutter:Widget (配置) → Element (位置) → Render (布局 + 绘制);Element 为性能而被复用。
  • BuildContext —— widget 在树中的位置;访问 MediaQuery、Theme、Navigator、InheritedWidget。
  • Material 和 Cupertino —— 用于 Google Material Design 3 和 Apple HIG 的两套 widget。
  • Key (ValueKey, ObjectKey, UniqueKey) —— 在列表中顺序/数量更改时标识 widget。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读