为 basic_flutter 项目生成统一的 DemoPage/DemoView 页面骨架,叶子 demo 使用 xxx_example.dart 命名,并按当前目录惯例与 CatalogEntry 架构接入
为 basic_flutter 项目生成风格统一的 demo 页面骨架,并接入当前 Catalog First 架构。
默认模式:
XxxDemoPage -> XxxDemoViewlib/demos/network/dio_example.dartlib/demos/layout/containers/align_example.dart复杂场景:
pages/、controllers/、providers/、cubits/、bindings/ 等子目录xxx_example.dart 继续作为对外入口lib/ 顶层新增页面文件。lib/demos/packages/:三方包、平台能力、工具封装演示lib/demos/basics/:基础示例和完整小型示例应用,例如 counter、getx_applib/demos/video/:视频播放相关示例,如 video_player、chewielib/demos/state_management/:provider、bloc、riverpod 等状态管理示例lib/demos/storage/:本地存储相关示例,如 shared_preferences、hive、secure_storagelib/demos/network/:网络请求相关示例,如 dio、httplib/demos/animation/:动画资源和播放示例lib/demos/layout/:布局和交互类示例lib/demos/showcase/:展示类示例lib/demos/basics/counter/counter_example.dart、lib/demos/state_management/provider/provider_example.dart。XxxDemoPage -> XxxDemoViewXxxDemoPage -> Stateful XxxDemoViewxxx_example.dart 作为入口,再拆 pages/ 等子目录xxx_example.dart。XxxDemoPage,优先使用 StatelessWidget。XxxDemoView。ScreenUtilInit 之类的外层包裹XxxDemoPage。XxxDemoPage 使用 StatefulWidget。class ToastDemoPage extends StatelessWidget {
const ToastDemoPage({super.key, required this.title});
final String title;
@override
Widget build(BuildContext context) {
return ToastDemoView(title: title);
}
}
XxxDemoView:单文件内承载 Scaffold 的真实页面组件。pages/ 目录中的真实页面组件,但 xxx_example.dart 仍然是统一入口。XxxDemoView;只有在页面明显变复杂时,才继续拆目录。StatelessWidget;需要 initState、setState、控制器生命周期时改用 StatefulWidget。await 后再更新 UI、弹 SnackBar、setState 或访问上下文时:
State 里优先使用 if (!mounted) return;BuildContext 时使用 if (!context.mounted) return;class XxxDemoView extends StatelessWidget {
const XxxDemoView({super.key, required this.title});
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(title)),
body: getBody(),
floatingActionButton: getFAB(),
);
}
Widget getBody() {
return const Center();
}
Widget getFAB() {
return FloatingActionButton(
onPressed: null,
child: const Icon(Icons.add),
);
}
}
floatingActionButton 和 getFAB(),不要为了统一而保留空实现。xxx_example.dart。pages/controllers/notifiers/cubits/providers/observers/bindings/xxx_example.dart 优先只保留对外入口、注入层、包裹层和必要的轻量生命周期逻辑。lib/demos/state_management/provider/lib/demos/state_management/bloc/lib/demos/state_management/riverpod/lib/demos/basics/getx_app/ToastDemoPage / ToastDemoView / packages/toast_example.dartProviderCounterDemoPage / CounterProviderPage / state_management/provider/provider_example.darttitle 默认与 demo 名称语义一致,例如 Toast、SharedPreferences、Counter Example。subtitle 默认与当前分组现有风格保持一致;若无额外说明,可与 title 主语义一致。getBody() 和 _buildBody()。getBody()getFAB()Widget getFAB(BuildContext context)。_buildBody()、_buildFab()。catalog.dart 接入。CatalogEntry。CatalogEntry.page(...)。CatalogEntry.catalog(...)。path 统一写相对路径:
basics、layout、networkcontainers、dio、shared-preferencesshared-preferencesscreen-utilsecure-storagepageBuilder 应直接返回 const XxxDemoPage(...)。/// Toast
/// https://pub.dev/packages/fluttertoast
const、final、强类型、显式返回类型。print;如需日志,使用 lib/core/utils/logger/。use_build_context_synchronously 规则,不要在缺少 mounted 检查时直接使用上下文。lib/core/utils/ 是否已有封装;若已有,优先复用项目统一封装,而不是重复直接调用第三方包 API。lib/core/utils/ui/toast.dartlib/core/utils/ui/notification.dartlib/core/utils/storage/shared_preferences.dartlib/core/utils/logger/logger.dartMaterialApp、GetMaterialApp。lib/demos/basics/getx_app/ 这种独立实验应用,才允许自带 GetMaterialApp。AppHome 展示首页顶层分组CatalogPage 展示分组列表CatalogPage 内通过 AppNavigator.pushPath(item.path) 进入最终示例页lib/demos/*/catalog.dart。lib/catalog/registry/catalog_registry.dartlib/app/router/app_router_config.dartfvm flutter analyzefvm flutter testCatalogPage 分组列表入口正常XxxDemoPage -> XxxDemoView。xxx_example.dart + pages/ 等子目录。XxxDemoPage 不承载复杂页面 UI 和业务细节,但允许承载轻量注入、包裹层和必要生命周期逻辑。XxxDemoView 或拆分后的页面组件使用 StatefulWidget。XxxDemoPage 使用 StatefulWidget。lib/demos/packages/toast_example.dart、lib/demos/packages/notification_example.dart、lib/demos/state_management/provider/provider_example.dart 一致的组织方式。