Flutter Stocks 演示应用实战:构建安装、Material 组件与 gen_l10n 国际化全流程解析
【免费下载链接】flutterFlutter makes it easy and fast to build beautiful apps for mobile and beyond项目地址: https://gitcode.com/GitHub_Trending/flutter41/flutter
Stocks 是 Flutter 仓库内置的演示应用(demo app),用于展示 Material Design 组件库及其他 Flutter 核心特性,同时它也是dev/benchmarks目录下的滚动性能测试对象。读完本篇,你将掌握 Stocks 应用的构建与安装方法、其入口路由与主题架构,以及基于gen_l10n工具链的 ARB 文件国际化完整工作流——从.arb文案文件、l10n.yaml配置到生成StockStrings类并接入MaterialApp的每一步都能直接复用到自己的项目中。
应用定位与仓库位置
根据 README.md,Stocks 的定位非常明确:"Demo app for the Material Design widgets and other features provided by Flutter",即一个展示 Material 组件与 Flutter 特性的演示应用。此外,README 还说明该应用已经完成了国际化("just enough to show how it's done"),作为gen_l10n工具的使用示例。
需要留意的是:README 中构建一节给出的路径cd $FLUTTER_ROOT/examples/stocks是该应用历史上所在的examples/目录;在当前仓库中,这个应用实际位于dev/benchmarks/test_apps/stocks,它同时承担着基准测试(benchmark)测试对象的角色——目录下带有test_driver/scroll_perf_test.dart这类驱动测试(详见文末"测试与性能驱动"一节)。
从源码结构看,应用主体由以下 Dart 文件组成(位于 lib/ 目录):
- main.dart:应用入口,负责主题、路由与本地化接入;
- stock_home.dart:主页,包含 TabBar、搜索、Drawer、底部弹层等 Material 组件的综合运用;
- stock_settings.dart:设置页,提供一系列渲染调试开关;
- stock_list.dart、stock_row.dart:股票列表与行组件;
- stock_data.dart:模拟数据源;
- i18n/:国际化资源与生成文件(ARB 文件、
StockStrings类及说明文档 regenerate.md)。
平台侧则包含标准的 Android(android/,带 Gradle lockfile)与 iOS(ios/,含 Xcode 工程与 AppIcon 资源集)工程目录。
构建与安装
README 给出的构建流程非常简单,前提条件是先按官方指南完成 Flutter SDK 的安装配置。完整的构建与安装步骤如下:
cd $FLUTTER_ROOT/examples/stocks # README 原始路径;当前仓库中对应 dev/benchmarks/test_apps/stocks flutter pub get flutter run --release其中flutter run --release一条命令同时完成构建与安装到设备两个动作,以 Release 模式启动应用。
结合当前仓库的 pubspec.yaml,可以补充几个对构建有实际影响的细节:
name: stocks environment: sdk: ^3.11.0-0 resolution: workspace dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter intl: any http: any dev_dependencies: flutter_test: sdk: flutter flutter_driver: sdk: flutter test: any flutter: generate: true uses-material-design: trueflutter_localizations与intl是国际化能力的依赖前提(下文详述),intl: any的写法依赖 pub 解析时与flutter_localizations所固定的版本保持一致;flutter: generate: true是关键开关:它让flutter pub get/flutter run等命令在构建前自动执行本地化代码生成,无需手工调用flutter gen-l10n;resolution: workspace表示该应用参与仓库级 Dart workspace 的依赖解析;flutter_driver与test作为 dev 依赖,支撑了后文的驱动级滚动性能测试。
入口架构:主题、路由与调试开关
main.dart 中的StocksAppState是理解整个应用的钥匙。它维护一个StockConfiguration配置对象,集中管理以下状态:
stockMode:optimistic(乐观)或pessimistic(悲观),分别映射到Brightness.light与Brightness.dark,即通过"情绪"切换明暗主题;backupMode:云端备份开关;- 一组渲染调试开关:
debugShowGrid、debugShowSizes、debugShowBaselines、debugShowLayers、debugShowPointers、debugShowRainbow,以及showPerformanceOverlay、showSemanticsDebugger。
build方法将这些配置落实到MaterialApp上:
return MaterialApp( title: 'Stocks', theme: theme, localizationsDelegates: StockStrings.localizationsDelegates, supportedLocales: StockStrings.supportedLocales, debugShowMaterialGrid: _configuration.debugShowGrid, showPerformanceOverlay: _configuration.showPerformanceOverlay, showSemanticsDebugger: _configuration.showSemanticsDebugger, routes: <String, WidgetBuilder>{ '/': (BuildContext context) => StockHome(stocks, _configuration, configurationUpdater), '/settings': (BuildContext context) => StockSettings(_configuration, configurationUpdater), }, onGenerateRoute: _getRoute, );从源码结构看,路由分为两类:routes表静态声明了'/'(主页 stock_home.dart 的StockHome)与'/settings'(stock_settings.dart 的StockSettings);而onGenerateRoute(_getRoute)动态处理'/stock'路径——把settings.arguments中的股票代码作为参数构建StockSymbolPage,这正是主页中Navigator.pushNamed(context, '/stock', arguments: stock.symbol)打开个股详情页的落点。
此外,StocksAppState还在assert块中把调试开关同步到package:flutter/rendering.dart的顶层布尔量(如debugPaintSizeEnabled、debugRepaintRainbowEnabled等)。这些开关只在调试模式生效,对应的设置项也只在 stock_settings.dart 的assert(() {...}())块内添加——这意味着 Release 构建中用户看不到"Show construction lines (for debugging)"这类仅调试可用的行,这是"用assert包裹仅调试功能"的范例写法。
主页StockHome则是一个 Material 组件的"博物馆":DefaultTabController+TabBar/TabBarView双 Tab(Market 与 Portfolio)、Drawer抽屉、PopupMenuButton弹出菜单(含动画速度调节,直接操作timeDilation)、TextField搜索栏(用LocalHistoryEntry使返回键可退出搜索)、FloatingActionButton加showModalBottomSheet底部弹层、SnackBar购买提示等,基本覆盖了 README 所称"Material Design widgets"演示的目标。
国际化(i18n):gen_l10n 完整工作流
README 的 Internationalization 一节指向 lib/i18n/regenerate.md,该文档与仓库源码一起,构成了一套可直接照搬的本地化方案。
工作流概览
lib/i18n/目录下的 ARB 文件是输入源:stocks_en.arb(模板)、stocks_en_US.arb、stocks_es.arb;flutter gen-l10n工具(由 pubspec 中generate: true驱动)根据 l10n.yaml 的选项,从 ARB 文件生成stock_strings.dart,其中包含StockStrings抽象类;- 应用通过
StockStrings.of(context)查找当前设备语言对应的本地化字符串; - 应用依赖 Dart 的
intl包完成底层消息处理。
模板文件 stocks_en.arb 中每个文案都附带@前缀的元数据描述,这是 ARB 规范推荐的写法:
{ "title": "Stocks", "@title": { "description": "Title for the Stocks application" }, "market": "MARKET", "@market": { "description": "Label for the Market tab" }, "portfolio": "PORTFOLIO", "@portfolio": { "description": "Label for the Portfolio tab" } }西班牙语文件 stocks_es.arb 提供了对应翻译("title": "Acciones"、"market": "MERCADO"、"portfolio": "CARTERA"),而 stocks_en_US.arb 目前与英文模板取值相同。按 regenerate.md 的说明:要更新英文和西班牙语的本地化,修改这三个 ARB 文件即可;要修改本地化工具的项目配置,则改l10n.yaml。
l10n.yaml 配置参数逐项说明
l10n.yaml 是这套方案的核心配置,文件内注释非常完整,整理如下:
| 配置项 | 当前取值 | 作用 |
|---|---|---|
arb-dir | lib/i18n | 输入 ARB 文件所在目录;未显式指定输出目录时,输出目录与输入目录一致(本例中生成文件就写回lib/i18n/) |
header-file | header.txt | 每个生成文件头部插入的自定义文件头 |
output-class | StockStrings | 应用中要使用的本地化类名,需在整个应用中导入 |
output-localization-file | stock_strings.dart | 生成文件的主文件名 |
template-arb-file | stocks_en.arb | 模板 ARB 文件,工具用它来校验其余 ARB 文件的键是否完整一致 |
nullable-getter | false | 生成非空StockStringsgetter,免去应用中的空值检查 |
format | true | 对生成的本地化文件运行 formatter |
其中 header.txt 的内容是版权声明加上// THE FOLLOWING FILES WERE GENERATED BY 'flutter gen-l10n'.的生成标记——在 stock_strings.dart 第 5 行可以看到它已注入生成文件头部。
生成类与语言回退链
生成的 stock_strings.dart 包含三个要点:
StockStrings抽象类:声明title、market、portfolio三个字符串 getter,提供of(BuildContext)、delegate、localizationsDelegates与supportedLocales静态成员。文档注释还特别提醒:iOS 应用需要在ios/Runner/Info.plist中通过 "Localizations" 项声明支持的语言,且该列表要与StockStrings.supportedLocales保持一致;supportedLocales:Locale('en')、Locale('en', 'US')、Locale('es');lookupStockStrings的回退逻辑:先按"语言+国家"精确匹配(en+US返回StockStringsEnUs),再按语言码兜底(en→StockStringsEn,es→StockStringsEs),都不匹配则抛出带工具报错提示的FlutterError。
regenerate.md 对继承链的描述是这套方案最容易被忽略但最关键的设计:StockStringsEn与StockStringsEs继承StockStrings,而StockStringsEnUs继承StockStringsEn——这使得en_US区域可以自动回退(fall back)到StockStringsEn中的消息。也就是说,未来若为en_US只翻译了market,其余文案会自然落到英文通用版本,翻译者无需覆盖全部键。
接入方式在 main.dart 中只用了两行(localizationsDelegates与supportedLocales),而StockStrings.localizationsDelegates内部已聚合了delegate、GlobalMaterialLocalizations.delegate、GlobalCupertinoLocalizations.delegate和GlobalWidgetsLocalizations.delegate四个委托。stock_home.dart 中的实际取词示例:
title: Text(StockStrings.of(context).title), // ... bottom: TabBar( tabs: <Widget>[ Tab(text: StockStrings.of(context).market), Tab(text: StockStrings.of(context).portfolio), ], ),这一行为有测试用例兜底验证:test/locale_test.dart 先断言默认环境下能看到MARKET,然后tester.binding.setLocale('es', '')切换语言并再次 pump,断言 Tab 文本变为MERCADO——恰好对应stocks_es.arb中的market翻译,闭环验证了 ARB → 生成类 → Widget 取值的整条链路。
图标制作说明
README 的 Icon 一节交代了应用图标的来源:使用 Android Asset Studio 在线工具制作,素材取自公共领域(public domain)的 "Tango Go Up" 剪贴画(OpenClipart 编号 30403),配色参数为前景色#607d8b、白色方形背景、无特效。生成产物就是android/app/src/main/res/mipmap-*/下从 mdpi 到 xxxhdpi 的各密度ic_launcher.png,以及 iOS 侧ios/Runner/Assets.xcassets/AppIcon.appiconset/下各尺寸的Icon-*.png。
测试与性能驱动
作为dev/benchmarks下的测试应用,Stocks 还附带两类自动化测试:
- 单元测试:除 locale_test.dart 外,还有
search_test.dart与icon_color_test.dart,且locale_test.dart通过stock_data.StockData.actuallyFetchData = false关闭真实数据抓取,保证测试可离线运行; - 驱动级滚动性能测试:test_driver/scroll_perf_test.dart 通过
FlutterDriver连接设备,用driver.traceAction包裹"对ValueKey('stock-list')找到的股票列表上下各滚动 5 次、每次 300 逻辑像素"的操作序列,再用TimelineSummary.summarize汇总 Timeline 并写入stocks_scroll_perf文件。这说明 Stocks 列表的ValueKey('stock-list')并非随便标注,而是为外部性能度量预留的锚点。
小结
Stocks 演示应用把 README 承诺的三件事落得相当扎实:用flutter run --release三步构建安装;用generate: true+l10n.yaml+ ARB 模板文件实现了一条"改 ARB 即更新本地化"的低摩擦国际化管线,其en_US → en的继承回退设计值得直接借鉴;同时它还以StockConfiguration+ 设置页开关的形式,演示了如何把 Flutter 的渲染调试工具暴露给最终用户界面。对读者而言,把 l10n.yaml 的七个参数、regenerate.md 的回退链说明和 main.dart 的两行接入代码组合起来,就是一个可以立即复现的 gen_l10n 最小完整方案。
【免费下载链接】flutterFlutter makes it easy and fast to build beautiful apps for mobile and beyond项目地址: https://gitcode.com/GitHub_Trending/flutter41/flutter
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考