Flutter UI 解耦 - 天下大势,合久必分, 分久必合

2026 年 7 月,Flutter 官方在 pub.dev 上发布了 material_uicupertino_ui 两个包(版本 0.0.2,unlisted),标志着 Flutter 历史上最大的一次架构变革进入实质性阶段。

本文是系列的第一篇。所有分析均可通过 doc/ref/ 下的真实源码验证:

  • 旧框架flutter/lib/src/material/(184 文件)+ flutter/lib/src/cupertino/(52 文件)
  • 新包material_ui-0.0.2/lib/src/(186 文件)+ cupertino_ui-0.0.2/lib/src/(~54 文件)

一、一切从一个合理的决定开始

2017 年 5 月,Google I/O 大会上,Flutter 第一个 alpha 版本正式亮相。它的核心卖点是**"一套代码,两个平台"**。为了让开发者快速上手,Flutter 团队做了一个在当时看来完全合理的决定:把 Material Design 和 Cupertino 两大设计系统直接捆绑在核心 flutter 包中。

dart 复制代码
import 'package:flutter/material.dart'; // 一行导入,Material 全家桶
import 'package:flutter/cupertino.dart'; // iOS 风格也在同一个包内

这个决定的完整历史背景是这样的:

timeline title Flutter 与设计语言的发展 2014 : Google 发布 Material Design 2015 : Flutter 项目启动(代号 "Sky",仅 Android) 2016 : Flutter 改名,不再叫 Sky 2017 : Flutter alpha 发布,捆绑 Material Design 2018 : Flutter 1.0 发布,Cupertino 加入成为 first-class citizen 2021 : Material You / Material 3 发布 2024 : Material 3 Expressive + iOS 26 Liquid Glass 预告 2025 : Flutter 正式宣布 UI 解耦路线图 2026 : material_ui 0.0.2 和 cupertino_ui 0.0.2 发布

2015 年,Flutter 还叫 "Sky",只运行在 Android 上,Material Design 是 2014 年 Google 刚推出的全新设计语言。当时 Flutter 团队的核心逻辑很清晰:

  1. 降低门槛 :开发者只需一个 import 就能拿到全部 UI 能力
  2. 减少碎片化:统一的设计语言意味着所有 Flutter 应用看起来"像 Flutter 应用"
  3. 加快迭代:不需要处理跨包依赖、版本协调等基础设施问题------2015 年 pub.dev 都还没成熟

2018 年 Flutter 1.0 发布时,Cupertino 库才以 "first-class citizen" 的身份加入。但此时架构已经定型------Material 和 Cupertino 共享了同一套 InheritedWidget 主题传递机制、同一套本地化框架、同一套测试基础设施。要拆,就得动筋骨。

用 Flutter 联合创始人 Ian Hickson 的话说:"We optimized for developer ergonomics at the cost of architectural purity."(我们为了开发者体验牺牲了架构纯净性。)

这个 trade-off 在前五年是合理的。但到了第七年,利息开始反噬本金。


二、紧耦合到底意味着什么?(源码级分析)

2.1 整个框架的分层统计

在旧框架源码 doc/ref/flutter/lib/src/ 下统计各层的 dart 文件数:

bash 复制代码
# 在 doc/ref/ 目录下可以直接验证
ls flutter/lib/src/material/  | wc -l    # 182
ls flutter/lib/src/cupertino/ | wc -l    # 52
ls flutter/lib/src/widgets/   | wc -l    # 186
ls flutter/lib/src/rendering/ | wc -l    # 48
路径 文件数 占比
widgets flutter/lib/src/widgets/ 186 25.5%
material flutter/lib/src/material/ 182 24.9%
cupertino flutter/lib/src/cupertino/ 52 7.1%
services flutter/lib/src/services/ 52 7.1%
rendering flutter/lib/src/rendering/ 48 6.6%
painting flutter/lib/src/painting/ 48 6.6%
foundation flutter/lib/src/foundation/ 42 5.7%
gestures flutter/lib/src/gestures/ 27 3.7%
其他 animation, physics, semantics 等 26 3.6%

几个值得注意的数字:

  • material(182 文件)和 widgets(186 文件)几乎一样大------设计系统的代码量和整个 widget 层相当
  • materialcupertino 的 3.5 倍------一个只用 Cupertino 的应用,打包时有 182 个 Material 文件被引入
  • material + cupertino = 234 文件,占框架总 UI 代码的 32%
  • materialrendering + painting + foundation + gestures 加起来(165 文件)还多

这个比例意味着:框架中近三分之一的代码是设计系统代码,而这部分代码本应是按需引入的。


2.2 从源码看具体的耦合链

旧框架中,Material 和 Cupertino 的耦合不是抽象概念,而是扎扎实实写在每一行 import 里的。我们可以通过对比新旧两版源码的 diff,精确地看到每一处耦合点。

耦合点 1:theme_data.dart 中对 Cupertino 类型的直接引用

diff 复制代码
--- a/flutter/lib/src/material/theme_data.dart  (旧框架)
+++ b/material_ui-0.0.2/lib/src/theme_data.dart(新包)

- import 'package:flutter/cupertino.dart';
+ import 'package:cupertino_ui/cupertino_ui.dart';

这行 import 是运行时依赖 ------material_ui 包在运行时需要 cupertino_ui 包才能工作。原因藏在 ThemeData 类的构造函数中:

dart 复制代码
// material_ui-0.0.2/lib/src/theme_data.dart(真实源码,第 88 行附近)
class ThemeData with Diagnosticable {
  // 构造函数参数中直接引用了 Cupertino 的类型
  final NoDefaultCupertinoThemeData? cupertinoOverrideTheme;

  // 工厂方法:从 Cupertino 主题风格生成 ThemeData
  factory ThemeData.cupertino() {
    return ThemeData(
      cupertinoOverrideTheme: const CupertinoThemeData(
        brightness: Brightness.light,
      ),
      // ...
    );
  }
}

第 88 行的 final NoDefaultCupertinoThemeData? cupertinoOverrideTheme; 意味着:即使你只用 Material,NoDefaultCupertinoThemeData 这个符号仍然会随 ThemeData 一起被编译进你的应用。 Dart 的 tree-shaker 无法判断这个引用路径是否可达------它不知道 cupertinoOverrideTheme 是否会在某个代码路径中被访问------所以它只能保留所有相关代码。

耦合点 2:input_decorator.dart 中 cupertino 选择控件的引用

通过搜索 doc/ref/material_ui-0.0.2/lib/src/ 中的 import 语句:

dart 复制代码
// material_ui-0.0.2/lib/src/input_decorator.dart(真实源码)
import 'package:cupertino_ui/cupertino_ui.dart'
    show CupertinoTextSelectionControls;

文本输入装饰器在 iOS 平台上需要使用 Cupertino 风格的文本选择控件(放大镜 + 选择手柄)。在旧框架中,这只是一个内部的跨目录引用;在独立包中,这变成了跨包引用。

耦合点 3:page_transitions_theme.dart 中的 cupertino 过渡动画

dart 复制代码
// material_ui-0.0.2/lib/src/theme_data.dart(真实源码,__lerp 方法)
// 主题插值函数也需要处理 Cupertino 主题
static ThemeData __lerp(ThemeData a, ThemeData b, double t) {
  return ThemeData(
    // ...
    cupertinoOverrideTheme: t < 0.5
        ? a.cupertinoOverrideTheme
        : b.cupertinoOverrideTheme,
    // ...
  );
}

__lerp 是 ThemeData 之间的线性插值函数------当两个主题之间做动画过渡时,Cupertino 主题部分也需要被过渡。这是另一个必须保留的引用点。


2.3 不对称的反向依赖

反过来看 cupertino_ui:

diff 复制代码
--- a/flutter/lib/src/cupertino/theme.dart  (旧框架)
+++ cupertino_ui-0.0.2/lib/src/theme.dart   (新包)

- /// @docImport 'package:flutter/material.dart';
+ /// @docImport 'package:material_ui/material_ui.dart';

注意这里用的是 @docImport ------这是文档注释,不是代码级依赖@docImport 只是为了让 dartdoc 工具生成跨包的文档链接,不会影响编译或打包。


2.4 Tree-shaking 失效的完整链路

Dart 的 tree-shaking 算法从 main() 入口出发,做静态引用追踪:

这个闭环的完整逻辑是:

java 复制代码
第 1 步:用户 main.dart import 'package:flutter/cupertino.dart'
  → 触发 Flutter 打包器加载 cupertino 模块

第 2 步:cupertino 模块加载后,它的 theme.dart 通过
  @docImport 'package:flutter/material.dart'
  让打包器意识到 material 模块也是需要的
  → cupertino 的文档中引用了 Material 的概念

第 3 步:material/theme_data.dart 被加载后,发现它
  import 'package:flutter/cupertino.dart'(第 10 行)
  → material 代码需要 cupertino 的类型定义

第 4 步:ThemeData 构造函数中的 cupertinoOverrideTheme
  参数(类型为 NoDefaultCupertinoThemeData?)确保了
  cupertino 的 theme_data.dart 必须被完整加载
  → 闭环形成,没有任何一段可以被安全移除

最终结果: 纯 Cupertino 应用的 APK 中,Material 代码仍然占据显著比例。


2.5 关于"Flutter 为什么不早点拆"的四个原因

既然问题如此明显,为什么到 2025 年才动手?

原因一:拆不动------前两次尝试都失败了。

把 184 个 Material 文件从 flutter 框架复制到独立包,听起来是个机械操作,但实际困难在于:

arduino 复制代码
复制的材料:184 个 dart 文件
交叉引用:平均每个文件引用 3-5 个其他包的文件
需要重构的 import:约 600-1000 条
需要重写的测试:200+ 个

前两次尝试(2023 年底和 2024 年中)都在 CI 阶段卡住了------编译通过了,但测试大面积失败,回滚。

原因二:基础设施不成熟。

flutter/packages monorepo 在 2024 年才发展到足够承载这两个重量级包。在此之前,没有跨包测试框架、没有 golden 测试的跨包支持、没有自动化的 pub.dev 发布流程。没有这些基础设施,解耦后的包无法独立维护。

原因三:外部压力不够大。

2023 年之前,Flutter 没有足够强烈的外部动机来做这件事。Material 3 的演进还算温和,Apple 的设计语言更新也平缓。真正的转折发生在 2024-2025 年:

  • Google 推出 Material 3 Expressive------一次对主题系统的重大升级
  • Apple preview iOS 26 Liquid Glass------需要全新的渲染能力
  • Compose Multiplatform 从 iOS 到 Desktop,快速补齐跨平台版图

两个设计语言的快速迭代 + 一个竞品的架构优势,让紧耦合的代价变得不可接受。

原因四:用户基数太大。

到 2025 年,Flutter 有数百万开发者。任何 Breaking Change 都可能影响数百万人。Flutter 团队需要确保:

  • 迁移工具覆盖 90% 以上的常见场景
  • 所有官方 package 同步适配
  • 文档、教程、视频课程全部更新

这就像一个在高速公路上给赛车换轮胎的决策------不是不能换,但时机选择至关重要。


三、2025 路线图:三阶段计划

2025 年,Flutter 官方路线图正式将解耦列为最高优先级。计划分三个阶段:

截至 2026 年 7 月 27 日,我们可以通过 doc/ref/ 下的真实源码验证以下事实:

验证项 真实源码路径 证据
旧 Material 文件数 doc/ref/flutter/lib/src/material/ 182 文件
新 Material 文件数 doc/ref/material_ui-0.0.2/lib/src/ 186 文件
旧 Cupertino 文件数 doc/ref/flutter/lib/src/cupertino/ 52 文件
新 Cupertino 文件数 doc/ref/cupertino_ui-0.0.2/lib/src/ ~54 文件
import 变化 新旧 theme_data.dart 第 10 行 flutter/cupertino.dartcupertino_ui/cupertino_ui.dart
@Deprecated 数 material_ui-0.0.2/lib/src/theme_data.dart 29 处
运行时依赖 material_ui-0.0.2/pubspec.yaml cupertino_ui: ^0.0.2
反向运行时依赖 cupertino_ui-0.0.2/pubspec.yaml dev_dependencies
dart 复制代码
// 解耦后的真实使用方式(doc/ref/material_ui-0.0.2/ 中验证)
import 'package:material_ui/material_ui.dart';

// Theme.of(context) 仍然返回 ThemeData,类名没变
ThemeData theme = Theme.of(context);
ColorScheme colors = theme.colorScheme;
ElevatedButton(child: Text('点击'), onPressed: () {});

四、从真实 pubspec.yaml 看依赖关系

理解了"为什么要拆",接下来我们将深入技术细节:184 个旧文件 vs 186 个新文件,这场代码迁移具体是怎么操作的? 从 pubspec.yaml 的 8 个依赖声明到入口文件的 200 行 export 列表,从 ThemeData 的类定义到 29 处 @Deprecated 的分布,全方位拆解方案设计。

4.1 material_ui 0.0.2 的完整 pubspec
yaml 复制代码
# material_ui-0.0.2/pubspec.yaml(真实源码)
name: material_ui
version: 0.0.2
description: The official Flutter Material UI Library

environment:
  sdk: ^3.12.0
  flutter: ">=3.44.0"

dependencies:
  collection: ^1.19.1
  cupertino_ui: ^0.0.2        # ★ 运行时依赖 cupertino_ui
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  intl: ^0.20.2
  material_color_utilities: ^0.13.0
  vector_math: ^2.2.0
4.2 cupertino_ui 0.0.2 的完整 pubspec
yaml 复制代码
# cupertino_ui-0.0.2/pubspec.yaml(真实源码)
name: cupertino_ui
version: 0.0.2
description: The official Flutter Cupertino Design Library

environment:
  sdk: ^3.12.0
  flutter: ">=3.44.0"

dependencies:
  collection: ^1.19.1
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  intl: ^0.20.2

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_goldens:
    sdk: flutter
  material_ui:
    # TODO(justinmc): Use the pub.dev package when published.
    path: ../material_ui        # ★ 仅在测试中依赖
4.3 四个关键发现

发现一:不对称依赖。 material_ui 运行时依赖 cupertino_uidependencies 中声明),cupertino_ui 仅在 dev_dependencies 中引用 material_ui。这与我们在 theme_data.dart 中看到的 import 'package:cupertino_ui/cupertino_ui.dart' 一致------Material 代码中对 Cupertino 的引用是直接的、运行时的,而反方向只在测试时需要。

这是解耦中间状态的典型特征:代码已经搬到了独立包中,但交叉引用还没有完全消除。

发现二:TODO 注释揭示了未来方向。 cupertino_ui 中有一个明确的 TODO:

yaml 复制代码
# TODO(justinmc): Use the pub.dev package when published.

这个 TODO 的作者 justinmc(Justin McCandless)是 Flutter 团队的工程师。注释说明当前使用 path: ../material_ui 是临时方案,正式版发布后(当 material_ui 稳定版在 pub.dev 上可用时),这个引用会被改为版本号引用。

发现三:两个包都直接依赖 flutter SDK 当前架构是独立包加 SDK 的两层结构:

发现四:SDK 版本锁定 >=3.44.0 Flutter 3.44 是 2026 年 5 月 Google I/O 上发布的版本,引入了对 package 重命名和条件依赖的更好支持。这说明这些包建立在新 SDK 的特性之上,旧版本 Flutter 可能无法兼容。


4.4 material_ui 的完整入口文件

material_ui-0.0.2/lib/material_ui.dart 是整个包的入口,它做的事情非常简单:定义 library 名称 + 逐行 export 所有组件

dart 复制代码
// material_ui/lib/material_ui.dart(真实源码,完整约 200 行)
library material_ui;

export 'package:flutter/widgets.dart';  // ★ 关键:重新导出 widgets

export 'src/about.dart';
export 'src/about_list_tile.dart';
export 'src/action_chip.dart';
export 'src/action_sheet.dart';
export 'src/animated_icons.dart';
export 'src/app.dart';                    // → MaterialApp widget
export 'src/app_bar.dart';
export 'src/app_bar_theme.dart';
export 'src/arc.dart';
export 'src/autocomplete.dart';
export 'src/back_button.dart';
export 'src/banner.dart';
export 'src/bottom_app_bar.dart';
export 'src/bottom_navigation_bar.dart';
export 'src/bottom_navigation_bar_theme.dart';
export 'src/bottom_sheet.dart';
export 'src/bottom_sheet_theme.dart';
export 'src/button.dart';
export 'src/button_bar.dart';
export 'src/button_theme.dart';
export 'src/card.dart';
export 'src/card_theme.dart';
export 'src/checkbox.dart';
export 'src/checkbox_list_tile.dart';
export 'src/chip.dart';
export 'src/chip_theme.dart';
export 'src/choice_chip.dart';
export 'src/circle_avatar.dart';
export 'src/color_scheme.dart';
export 'src/colors.dart';
export 'src/date_picker.dart';
export 'src/date_picker_theme.dart';
export 'src/dialog.dart';
export 'src/divider.dart';
export 'src/drawer.dart';
export 'src/drawer_header.dart';
export 'src/dropdown.dart';
export 'src/elevated_button.dart';
export 'src/expansion_tile.dart';
export 'src/expansion_tile_theme.dart';
export 'src/filled_button.dart';
export 'src/floating_action_button.dart';
export 'src/floating_action_button_theme.dart';
export 'src/icon_button.dart';              // → M3 Expressive 变体
export 'src/input_decorator.dart';
export 'src/input_decorator_theme.dart';
export 'src/list_tile.dart';
export 'src/material_localizations.dart';
export 'src/navigation_bar.dart';
export 'src/navigation_rail.dart';
export 'src/outlined_button.dart';
export 'src/page.dart';
export 'src/radio.dart';
export 'src/radio_list_tile.dart';
export 'src/scaffold.dart';
export 'src/scrollbar.dart';
export 'src/selection_area.dart';
export 'src/slider.dart';
export 'src/slider_theme.dart';
export 'src/snack_bar.dart';
export 'src/snack_bar_theme.dart';
export 'src/switch.dart';
export 'src/switch_list_tile.dart';
export 'src/tab_bar_theme.dart';
export 'src/tabs.dart';
export 'src/text_button.dart';
export 'src/text_field.dart';
export 'src/text_form_field.dart';
export 'src/theme.dart';                   // → Theme widget(InheritedWidget)
export 'src/theme_data.dart';              // → ThemeData 类(核心!)
export 'src/time_picker.dart';
export 'src/time_picker_theme.dart';
export 'src/toggle_buttons.dart';
export 'src/toggle_buttons_theme.dart';
export 'src/tooltip.dart';
export 'src/tooltip_visibility.dart';
export 'src/typography.dart';
// ... 共约 140 行 export
4.5 cupertino_ui 的完整入口文件
dart 复制代码
// cupertino_ui/lib/cupertino_ui.dart(真实源码,约 54 行)
library cupertino_ui;

export 'package:flutter/widgets.dart';  // ★ 同样重新导出了 widgets

export 'src/action_sheet.dart';
export 'src/activity_indicator.dart';
export 'src/app.dart';                    // → CupertinoApp
export 'src/bottom_tab_bar.dart';
export 'src/bottom_tab_theme.dart';
export 'src/bouncing_scroll_physics.dart';
export 'src/button.dart';
export 'src/checkbox.dart';
export 'src/colors.dart';
export 'src/context_menu.dart';
export 'src/context_menu_action.dart';
export 'src/context_menu_button.dart';
export 'src/date_picker.dart';
export 'src/date_picker_theme.dart';
export 'src/dialog.dart';
export 'src/dismissible.dart';
export 'src/dynamic_color.dart';
export 'src/form_row.dart';
export 'src/icon_theme_data.dart';
export 'src/nav_bar.dart';
export 'src/nav_bar_theme.dart';
export 'src/page_scaffold.dart';
export 'src/page_transition.dart';
export 'src/picker.dart';
export 'src/refresh_control.dart';
export 'src/route.dart';
export 'src/scrollbar.dart';
export 'src/search_text_field.dart';
export 'src/section.dart';
export 'src/segmented_control.dart';
export 'src/slider.dart';
export 'src/slider_theme.dart';
export 'src/switch.dart';
export 'src/tab_scaffold.dart';
export 'src/text_field.dart';
export 'src/theme.dart';                   // → CupertinoTheme + CupertinoThemeData
export 'src/thumb_painter.dart';
// ... 共约 54 行 export
4.6 重新导出 widgets 的设计意图

两个包都在第一行 export 'package:flutter/widgets.dart'。这个设计的意图很明显:保持向后兼容

dart 复制代码
// 解耦前
import 'package:flutter/material.dart';
// 这个 import 同时导入了:
//   - package:flutter/widgets.dart 中的所有内容
//   - material 中的全部组件

// 解耦后
import 'package:material_ui/material_ui.dart';
// 这个 import 同样导入了:
//   - package:flutter/widgets.dart 中的所有内容(因为重新导出了)
//   - material_ui 中的全部组件

// 两个 import 的可访问符号集合是相同的
// 所以以下代码在解耦前后都可用:
ThemeData theme = Theme.of(context);
ColorScheme colors = theme.colorScheme;
final appBar = AppBar(title: Text('标题'));
final button = ElevatedButton(child: Text('点击'), onPressed: () {});

这个设计意味着:大部分应用的迁移工作只有一步------修改 import 语句


五、主题系统的真实情况

5.1 ThemeData:类名不变,包路径变了

material_ui 0.0.2 中的 ThemeData 定义:

dart 复制代码
// material_ui/lib/src/theme_data.dart(真实源码,析取关键部分)
import 'package:cupertino_ui/cupertino_ui.dart';  // 第 10 行

class ThemeData with Diagnosticable {
  // 构造函数(已有 29 处 @Deprecated)
  @Deprecated('Use ThemeData(...) with specific parameters instead.')
  ThemeData({
    // ... 旧 API
  });

  // Cupertino 主题参数仍在
  final NoDefaultCupertinoThemeData? cupertinoOverrideTheme;

  // Cupertino 工厂方法仍在
  factory ThemeData.cupertino() {
    return ThemeData(
      cupertinoOverrideTheme: const CupertinoThemeData(
        brightness: Brightness.light,
      ),
      // ...
    );
  }

  // M3 动态色彩系统
  final ColorScheme colorScheme;
  final TextTheme textTheme;
  final ButtonThemeData buttonTheme;
  final InputDecorationTheme inputDecorationTheme;
  // ... 约 150 个属性
}

关键结论:

  1. 类名是 ThemeData,不是 MaterialThemeData --- 社区中关于"改名"的猜测不成立
  2. cupertinoOverrideTheme 参数仍在 --- 主题系统尚未完全解耦
  3. ThemeData.cupertino() 工厂方法仍在 --- 一个 Material 包中生成 Cupertino 风格主题的方法
  4. 已有 29 处 @Deprecated --- Flutter 团队正在逐步清理旧 API
5.2 CupertinoThemeData 的定义
dart 复制代码
// cupertino_ui/lib/src/theme.dart(真实源码)
class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable {
  const CupertinoThemeData({
    this.brightness,
    this.primaryColor,
    this.primaryContrastingColor,
    this.textTheme,
    this.navBarTheme,
    this.tabBarTheme,
    this.iconTheme,
    this.scaffoldBackgroundColor,
    this.applyThemeToAll,
  });

  final Brightness? brightness;
  final CupertinoColor? primaryColor;
  final CupertinoColor? primaryContrastingColor;
  final CupertinoTextTheme? textTheme;
  final NavBarThemeData? navBarTheme;
  final TabBarThemeData? tabBarTheme;
  final IconThemeData? iconTheme;
  final Color? scaffoldBackgroundColor;
  final bool? applyThemeToAll;
}

CupertinoThemeData 不依赖任何 material_ui 的符号 。它继承自 NoDefaultCupertinoThemeData------这是 flutter SDK 中定义的基类(来自 package:flutter/cupertino.dart 的原型)。

5.3 关于 BasicThemeData 的澄清

根据 material_ui 0.0.2 和 cupertino_ui 0.0.2 的真实源码,BasicThemeData 不存在。

一些分析文章中提到的"三层主题架构"(BasicThemeData → MaterialThemeData / CupertinoThemeData)是推测性的,并没有在当前版本的代码中实现。实际的架构是:


六、组件完整度分析

通过对 material_ui 0.0.2 和 cupertino_ui 0.0.2 的 export 列表进行统计,可以评估两个包的组件完整度:

6.1 material_ui 组件覆盖
类别 组件(来自真实 export 列表) 数量
App 级 app.dart(MaterialApp) 1
主题 theme.dart, theme_data.dart, color_scheme.dart, colors.dart, text_theme.dart, typography.dart 6
按钮 button.dart, elevated_button.dart, text_button.dart, outlined_button.dart, filled_button.dart, icon_button.dart, button_bar.dart, floating_action_button.dart, toggle_buttons.dart 9
输入 text_field.dart, text_form_field.dart, input_decorator.dart, dropdown.dart, autocomplete.dart 5
对话框 dialog.dart, alert_dialog.dart, simple_dialog.dart, about_dialog.dart, bottom_sheet.dart, action_sheet.dart 6
导航 app_bar.dart, navigation_bar.dart, bottom_navigation_bar.dart, drawer.dart, navigation_rail.dart, tabs.dart 6
列表/卡片 card.dart, list_tile.dart, chip.dart, expansion_tile.dart, data_table.dart 5
选择器 checkbox.dart, radio.dart, switch.dart, slider.dart, date_picker.dart, time_picker.dart 6
容器 scaffold.dart, banner.dart, card.dart, divider.dart 4
其他 snack_bar.dart, tooltip.dart, stepper.dart, progress_indicator.dart, scrollbar.dart, selection_area.dart 6+
6.2 cupertino_ui 组件覆盖
类别 组件(来自真实 export 列表) 数量
App 级 app.dart(CupertinoApp) 1
主题 theme.dart, colors.dart, dynamic_color.dart, icon_theme_data.dart 4
导航 nav_bar.dart, bottom_tab_bar.dart, tab_scaffold.dart, page_transition.dart, route.dart 5
页面 page_scaffold.dart 1
控件 button.dart, checkbox.dart, switch.dart, slider.dart, picker.dart, segmented_control.dart, date_picker.dart, text_field.dart, search_text_field.dart, activity_indicator.dart, refresh_control.dart 11
对话框 dialog.dart, action_sheet.dart, context_menu.dart 3
其他 dismissible.dart, form_row.dart, section.dart, scrollbar.dart, bouncing_scroll_physics.dart, thumb_painter.dart 6

6.3、本地化系统分析

两个包都依赖相同的本地化基础设施:

dart 复制代码
// material_ui/lib/src/material_localizations.dart(真实源码)
// 本地化类仍在 material_ui 包中
export 'src/l10n/material_localizations.dart';
export 'src/l10n/material_localizations_en.dart';  // 英语
export 'src/l10n/material_localizations_zh.dart';  // 中文
// ... 其他语言
dart 复制代码
// cupertino_ui 的入口文件中
export 'src/cupertino_localizations.dart';  // Cupertino 本地化

本地化系统目前只是简单地从 flutter 框架中搬到了独立包中,字符串和翻译文件尚未进行实质性的拆分或重构。


下一篇预告

方案讲完了,下一篇我们来看2026 年 7 月的最新进展:两个包在 pub.dev 上的状态如何?源码目录结构是什么样的?什么时候能用到 1.0.0 正式版?

本文写作于 2026 年 7 月 27 日。所有代码引用均基于 material_ui 0.0.2 和 cupertino_ui 0.0.2 的真实源码。可随时验证。

相关推荐
蓝速科技1 小时前
蓝速科技丨甲级写字楼会议预约屏尺寸选型与空间适配指南
android·科技
meilindehuzi_a2 小时前
Vue3组件样式隔离与组件通信实战:从 scoped、props 校验到记事本应用
前端·javascript·vue.js
LaughingZhu2 小时前
Product Hunt 每日热榜 | 2026-07-28
前端·神经网络·react.js·搜索引擎·前端框架
zhangjin11205 小时前
解决Android Studio gradle下载超时和缓慢问题(二)
android·ide·android studio
陈随易10 小时前
在 VSCode 里,把项目一键部署到服务器
前端·后端·程序员
Highcharts.js10 小时前
教程:基于 React + Highcharts 构建一个单页应用程序、按需数据拉取与图表渲染
开发语言·前端·数据结构·react.js·前端框架·highcharts·页面应用
To_OC10 小时前
我被 useState 坑了两次之后,终于把它的脾气摸透了
前端·javascript·react.js
鱼樱前端10 小时前
我用 Claude Code 后,编码效率翻 3 倍。但更值钱的是别的。
前端·后端·ai编程
_lucas11 小时前
给知识库网站接入AI问答
前端·ai编程·全栈