flutter架 构项目基础

This commit is contained in:
崔宝新
2026-09-04 15:22:20 +08:00
parent 70967229d0
commit 0c5aee59c0
265 changed files with 35484 additions and 0 deletions
+317
View File
@@ -0,0 +1,317 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:new_learn/core/components/video_player_page.dart';
import 'package:new_learn/features/auth/login_page.dart';
import 'package:new_learn/pages/demo/align_demo.dart';
import 'package:new_learn/pages/demo/animation_demo.dart';
import 'package:new_learn/pages/demo/form_demo.dart';
import 'package:new_learn/pages/demo/grid_demo.dart';
import 'package:new_learn/pages/demo/image_demo.dart';
import 'package:new_learn/pages/demo/input_demo.dart';
import 'package:new_learn/pages/demo/isar_watch_demo.dart';
import 'package:new_learn/pages/demo/list_demo.dart';
import 'package:new_learn/pages/demo/note_picker_demo.dart';
import 'package:new_learn/pages/demo/oss_upload_demo.dart';
import 'package:new_learn/pages/demo/audio_player_demo.dart';
import 'package:new_learn/pages/demo/rich_text_demo.dart';
import 'package:new_learn/pages/demo/dio_demo.dart';
import 'package:new_learn/pages/demo/dio_pro_demo.dart';
import 'package:new_learn/pages/demo/responsive_demo.dart';
import 'package:new_learn/pages/demo/share_demo.dart';
import 'package:new_learn/pages/demo/seed_palette_demo.dart';
import 'package:new_learn/pages/demo/sliver_demo.dart';
import 'package:new_learn/pages/demo/stack_demo.dart';
import 'package:new_learn/pages/demo/theme_demo.dart';
import 'package:new_learn/pages/demo/text_demo.dart';
import 'package:new_learn/pages/demo/wrong_flow_demo.dart';
import 'package:new_learn/pages/demo/smooth_sheet_demo.dart';
import 'package:new_learn/pages/demo/wrap_demo.dart';
import 'package:new_learn/pages/demo/exam_demo.dart';
/// ============================================================
/// 【TaskPage】「任务」tab 页 —— 学习 Demo 汇总入口
///
/// 一、本页作用:
/// 把之前学的所有组件 Demo 收进一个列表,点击每一项通过
/// Navigator.push 路由跳转到对应页面 —— 这就是真实 App 里
/// 「列表 → 详情」的跳转模型。
///
/// 二、路由跳转的两种写法(都可用):
/// 1. MaterialPageRoute:无需注册路由表,即写即用(本页采用);
/// 2. 命名路由 pushNamed:需在 MaterialApp.routes 里先注册。
/// 推荐本页方式:页面少时最简单;页面多了再统一用命名路由。
///
/// 三、结构化知识点:
/// _DemoItem 是纯数据模型(标题/副标题/图标/构造器),
/// 列表只用数据驱动生成 UI,新增一个 Demo 只需加一行数据。
/// ============================================================
class TaskPage extends StatelessWidget {
const TaskPage({super.key});
/// 全部学习 Demo 的数据清单(新增 Demo 只需在这里加一行)
///
/// 每行四项:标题 / 副标题 / 图标 / 页面构造器(用 _page 包装)。
/// 写页面构造器的三种姿势(任选,见 _page 函数注释):
/// - _page(LoginPage.new) :构造函数 tear-off(最简洁);
/// - 需要给页面传参就写闭包,
/// 如 _page(() => VideoPlayerPage(url: '...'));
/// - 页面能 const 就写 _page(() => const Xxx()),享 const 优化。
/// _page 内部是惰性创建:点击列表项时才 new 页面,不点不实例化。
static final List<_DemoItem> _demos = [
_DemoItem(
'登录页(真实接口)',
'账号/密码 + 协议 + POST /api/v1/User/Login',
Icons.login,
_page(LoginPage.new),
),
_DemoItem(
'Align 对齐布局',
'Alignment 定位 + SizedBox 尺寸',
Icons.align_horizontal_left,
_page(AlignDemoPage.new),
),
_DemoItem(
'Wrap 自动换行 + Chip 标签',
'流式布局、ActionChip/FilterChip',
Icons.wrap_text,
_page(WrapDemoPage.new),
),
_DemoItem(
'Stack 层叠布局',
'Positioned 定位 + 角标',
Icons.layers,
_page(StackDemoPage.new),
),
_DemoItem(
'TextField 输入框',
'controller + dispose + 密码可见',
Icons.text_fields,
_page(InputDemoPage.new),
),
_DemoItem(
'表单校验 Form',
'validator 规则 + 即时校验 + 两段式提交',
Icons.rule,
_page(FormDemoPage.new),
),
_DemoItem(
'动画体系',
'隐式动画 + 答题反馈 + Hero + 自绘进度环',
Icons.auto_awesome,
_page(AnimationDemoPage.new),
),
_DemoItem(
'品牌换肤(两级主题)',
'一级品牌色板 + 二级页面细节(SkyBlue/Red)',
Icons.palette_outlined,
_page(ThemeDemoPage.new),
),
_DemoItem(
'Seed 色板(主题生效演示)',
'Material 组件颜色全部来自 colorSchemeSeed 自动生成',
Icons.palette,
_page(SeedPaletteDemoPage.new),
),
_DemoItem(
'Isar watch 响应式',
'错题本:数据库变化自动刷新(仅真机)',
Icons.sync,
_page(IsarWatchDemoPage.new),
),
_DemoItem(
'接口+Isar+watch 链路',
'答题→接口上报→错题本自动刷新(仅真机)',
Icons.sync_alt,
_page(WrongFlowDemoPage.new),
),
_DemoItem(
'Text 文本组件',
'样式/截断/富文本/手势',
Icons.title,
_page(TextDemoPage.new),
),
_DemoItem(
'Image 图片组件',
'网络图/本地图/圆角/圆形头像',
Icons.image,
_page(ImageDemoPage.new),
),
_DemoItem(
'ListView 列表',
'下拉刷新 + 上拉加载 + 回到顶部',
Icons.view_list,
_page(ListDemoPage.new),
),
_DemoItem(
'GridView 网格',
'count/builder/extent 三种构造',
Icons.grid_view,
_page(GridDemoPage.new),
),
_DemoItem(
'CustomScrollView 混排',
'Sliver 系列 + 可折叠头部',
Icons.view_day,
_page(SliverDemoPage.new),
),
_DemoItem(
'Dio 网络请求封装',
'拦截器 + 错误映射 + 模型',
Icons.cloud_download,
_page(DioDemoPage.new),
),
_DemoItem(
'Dio 生产级深化',
'取消请求 + 进度回调 + 失败重试',
Icons.downloading,
_page(DioProDemoPage.new),
),
_DemoItem(
'笔记图片选择',
'相册多选/拍照 + 缩略图 + 上传占位',
Icons.photo_library_outlined,
_page(NotePickerPage.new),
),
_DemoItem(
'OSS 直传(V4 签名)',
'客户端签名 + PUT 直传阿里云 OSS + 进度条',
Icons.cloud_upload_outlined,
_page(OssUploadDemoPage.new),
),
_DemoItem(
'视频播放',
'video_player + chewie 在线点播',
Icons.play_circle_outline,
// Flutter 官方文档示例视频(bee.mp4),国内网络可直连;
// 以后接真实课程视频时把 url 换成后端地址即可
_page(
() => const VideoPlayerPage(
url:
'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4',
title: '视频播放',
),
),
),
_DemoItem(
'音频播放',
'just_audio 控制条(播放/进度/倍速/循环)',
Icons.music_note,
_page(AudioPlayerDemoPage.new),
),
_DemoItem(
'富文本渲染',
'题目/解析 HTML → widget(audio 自动换组件)',
Icons.text_snippet_outlined,
_page(RichTextDemoPage.new),
),
_DemoItem(
'响应式布局 手机 vs Pad',
'断点判断 + 单列/多列切换',
Icons.phone_iphone,
_page(ResponsiveDemoPage.new),
),
_DemoItem(
'分享功能',
'文本/图片/Widget截图分享(海报)',
Icons.share_outlined,
_page(ShareDemoPage.new),
),
_DemoItem(
'常驻多停靠底部面板',
'smooth_sheets · 3 停靠点 · 内部 ListView 联动',
Icons.pan_tool_outlined,
_page(SmoothSheetDemoPage.new),
),
_DemoItem(
'试卷练习(大数据滑动)',
'PageView.builder 100题 + 题型分发 + 续答持久化',
Icons.description_outlined,
_page(ExamDemoPage.new),
),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('任务'),
centerTitle: true,
),
body: ListView.separated(
padding: EdgeInsets.all(16.w),
itemCount: _demos.length,
separatorBuilder: (_, _) => SizedBox(height: 10.h),
itemBuilder: (context, index) {
final demo = _demos[index];
return Card(
elevation: 0,
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.r),
side: const BorderSide(color: Color(0xFFEEF1F5)),
),
child: ListTile(
leading: Container(
width: 40.w,
height: 40.h,
decoration: BoxDecoration(
color: const Color(0xFFE8F0FE),
borderRadius: BorderRadius.circular(10.r),
),
child: Icon(demo.icon, color: const Color(0xFF3B82F6)),
),
title: Text(
demo.title,
style: TextStyle(
fontSize: 15.sp,
fontWeight: FontWeight.w600,
color: const Color(0xFF333333),
),
),
subtitle: Text(
demo.subtitle,
style: TextStyle(fontSize: 12.sp, color: const Color(0xFF999999)),
),
trailing: const Icon(
Icons.chevron_right,
color: Color(0xFFC0C6CF),
),
// 点击 → 路由跳转到对应 Demo 页面
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(builder: demo.builder),
);
},
),
);
},
),
);
}
}
/// 把一个页面构造函数包装成 WidgetBuilder(惰性创建,点击才实例化)
///
/// 原理拆解(对照 _DemoItem.builder 的类型 WidgetBuilder):
/// - WidgetBuilder = Widget Function(BuildContext context),带 context 参数;
/// - 列表项只需要"无参创建页面",用不到 context → _page 把它吞掉;
/// - _page(Xxx.new) 里的 .new 是【构造函数 tear-off】(Dart 2.15+ 语法),
/// 类型为 `Xxx Function()`,等价手写 `() => Xxx()`。
///
/// 三种等价写法(效果相同):
/// _page(Xxx.new) // tear-off,最简洁
/// _page(() => const Xxx()) // 显式闭包 + const 构造(享 const 优化)
/// (_) => const Xxx() // 不用 _page,直接就是 WidgetBuilder
WidgetBuilder _page(Widget Function() create) {
return (_) => create();
}
/// Demo 列表项数据模型
class _DemoItem {
const _DemoItem(this.title, this.subtitle, this.icon, this.builder);
final String title;
final String subtitle;
final IconData icon;
final WidgetBuilder builder;
}