Skip to content

flutter 依赖

  • 网络请求:dio

  • responsive_framework

    • 设置响应式布局
  • riverpod

    • 用途:将你带有 @riverpod 注解的函数或类,转化为 UI 可用的 fetchUserProvidercounterProvider
    • 不运行后果:你写的 extends _$Counter 会持续报错,且 UI 无法找到对应的 Provider。
  • freezed

    • 用途:生成不可变对象。它会自动帮你写好 copyWith==hashCode(这是实现你最开始要求的 Set 集合存放对象自动去重 的核心逻辑)。
    • 不运行后果:无法使用复杂的模型类。
  • json_serializable

    • 用途:生成 fromJSONtoJSON 的具体实现代码。
    • 不运行后果:无法自动将后端返回的 Map 数据转换为 Dart 对象。
  • 资源与路由优化(推荐生成)

这些库虽然可选,但在 2026 年的规范项目中通常都会使用:

  • flutter_gen_runner
    • 用途:将你的图片(Assets)和字体自动转化为代码变量。
    • 效果:你可以写 Assets.images.logo.path 而不是手动打字符串 "assets/logo.png"
  • go_router_builder
    • 用途:为 GoRouter 提供类型安全的路由跳转。
    • 效果:避免手动写字符串路径,防止商城项目页面多了之后跳转出错。
  • flutter_secure_storage : 安全存储
  • shared_preferences:持久话kv存储
name: groe_app_pad
description: "A new Flutter project."
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1
environment:
sdk: ^3.9.2
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
cupertino_icons: ^1.0.8
collection: ^1.19.1
dio: ^5.9.2
flutter_riverpod: ^3.0.0
go_router: ^17.1.0
responsive_framework: ^1.5.1
flutter_secure_storage: ^10.0.0
webview_flutter: ^4.13.1
flutter_staggered_grid_view: ^0.7.0
mobile_scanner: ^7.2.0
intl: any
shared_preferences: ^2.5.5
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^5.0.0
flutter_gen_runner: ^5.13.0+1
build_runner: ^2.9.0
flutter:
generate: true
uses-material-design: true
assets:
- assets/images/
- assets/html/
flutter_gen:
output: lib/gen/
line_length: 100
说明
名称groe_app_pad
SDK^3.9.2(Dart 3.9 及以上)
发布publish_to: 'none' 表示不发布到 pub.dev,私有应用

依赖版本约束作用简述
flutterSDKFlutter 框架本体。
flutter_localizationsSDK官方本地化(MaterialApplocalizationsDelegates 等),与 intl、ARB 生成代码配合做多语言。
cupertino_icons^1.0.8iOS 风格图标字体,配合 CupertinoIcons 使用。
collection^1.19.1集合工具(如 groupByfirstWhereOrNull 等),减少手写循环与空安全样板代码。
dio^5.9.2HTTP 客户端:拦截器、超时、下载、FormData 等,适合对接 REST API(项目里建议与统一 Dio 实例、拦截器一起用)。
flutter_riverpod^3.0.0状态管理与依赖注入:Provider / Notifier 等,与 UI 解耦、可测试。
go_router^17.1.0声明式路由与深链接,替代手写 Navigator 栈管理,适合多页面/平板布局。
responsive_framework^1.5.1响应式断点、缩放或约束布局,让同一套 UI 在不同屏幕宽度下更易适配。
flutter_secure_storage^10.0.0安全存储(Keychain / Keystore 等),适合存 token、密钥等敏感数据,优于明文 SharedPreferences
webview_flutter^4.13.1内嵌 WebView,用于展示 H5、活动页、文档等与 assets/html/ 本地页配合。
flutter_staggered_grid_view^0.7.0瀑布流/不规则网格(多列高度不一),适合图片墙、卡片瀑布布局。
mobile_scanner^7.2.0相机扫码(二维码/条码等),依赖平台相机权限与原生实现。
intlany日期/数字/消息格式化;flutter_localizationsgen-l10n 常会间接依赖它,any 表示由解析器选兼容版本(注意:生产环境若需可复现构建,可改为固定版本范围)。
shared_preferences^2.5.5轻量键值持久化(用户设置、非敏感标记等),数据存于平台偏好存储,不宜存高敏感信息。

依赖版本约束作用简述
flutter_testSDK单元测试、Widget 测试、flutter test 所需。
flutter_lints^5.0.0官方推荐 lint 集合,配合 analysis_options.yaml 统一代码风格与静态检查。
build_runner^2.9.0运行代码生成任务的总入口(监听模式 watch、一次性 build)。
flutter_gen_runner^5.13.0+1根据 pubspecflutter.assets 等生成类型安全的资源访问代码(与下方 flutter_gen 配置对应)。

flutterflutter_gen(与依赖相关的配置)

Section titled “flutter 与 flutter_gen(与依赖相关的配置)”
配置作用
generate: true启用 Flutter 内置生成器(例如 gen-l10n,从 l10n.yaml + ARB 生成 app_localizations*.dart)。
uses-material-design: true打包 Material 图标字体。
assetsassets/images/assets/html/ 声明给打包与(可选)flutter_gen 扫描。
flutter_gen.output: lib/gen/flutter_gen 生成的资源 Dart 代码输出到 lib/gen/,避免手写字符串路径。
flutter_gen.line_length: 100生成代码换行宽度,与团队格式化习惯对齐。

  1. intl: any:能少操心版本冲突,但 CI 可重复性略差;若团队介意,可改为例如 intl: ^0.20.2(以当前 Flutter 解析结果为准)。
  2. 敏感数据:token 等优先 flutter_secure_storage;一般配置用 shared_preferences。
  3. 网络:业务层用 dio,路由用 go_router,全局状态用 flutter_riverpod,与你们架构规则里的分层一致即可。

如果你希望这份内容落盘成仓库里的 docs/DEPENDENCIES.md,可以说一下目标路径,我可以按你仓库习惯写好一版文件内容(你本地保存或让我改仓库都行)。

响应式框架responsive_framework自动处理断点,支持 UI 等比缩放或重排。
自适应导航flutter_adaptive_scaffold官方出品,快速实现手机/平板/桌面三端导航切换。

方案

维度flutter_screenutil (比例缩放派)responsive_framework (自适应布局派)
核心逻辑等比拉伸/缩小。所有组件随屏幕尺寸变大而变大,变小而变小。布局重组/断点控制。小屏堆叠、大屏分栏或自动扩充内容。
代码习惯必须在每个宽高、字号后加 .w, .h, .sp直接写数字,在全局或局部配置断点行为。
Pad 表现像一个“巨型手机版”。按钮和文字会变得很大。像“专业 Pad 版”。按钮大小不变,但显示的商品列数和内容变多。
2026 年地位属于UI 适配工具。属于布局架构工具。

等比缩放和设置断点

// iPad/桌面保持固定最大宽度,小屏按 1024 设计稿等比缩放。
final content = ResponsiveBreakpoints.builder(
child: Builder(
builder: (context) {
final enableScale = !context.isTabletUp;
return MaxWidthBox(
maxWidth: 1400,
child: ClipRect(
child: ResponsiveScaledBox(
// < 600:按 1024 基准做等比缩放(开启)
// >= 600:不做全局等比缩放(关闭)
width: enableScale ? 1024 : null,
child: DismissKeyboardOnTap(
child: child ?? const SizedBox.shrink(),
),
),
),
);
},
),
breakpoints: const [
/// 设下不同设备的断点
Breakpoint(start: 0, end: 599, name: MOBILE),
Breakpoint(start: 750, end: 1023, name: TABLET),
Breakpoint(start: 1024, end: 3000, name: DESKTOP),
],
);
  • 设置扩展
import 'package:flutter/material.dart';
import 'package:groe_app_pad/l10n/app_localizations.dart';
import 'package:responsive_framework/responsive_framework.dart';
extension BuildContextX on BuildContext {
bool get isTabletUp => ResponsiveBreakpoints.of(this).largerOrEqualTo(TABLET);
AppLocalizations get l10n => AppLocalizations.of(this)!;
}
// 使用
@override
Widget build(BuildContext context) {
final isTabletUp = context.isTabletUp;
// 当然也可以直接这样使用
final isTablet = ResponsiveBreakpoints.of(context).isTablet;
}

2. MaxWidthBox (最大宽度锁定) —— 解决 2080px 散架问题

Section titled “2. MaxWidthBox (最大宽度锁定) —— 解决 2080px 散架问题”

当你锁定基准宽度为 600dp,但在 2080px 的超宽屏(如 4K 屏)上运行时,即使有缩放,UI 也会因为拉伸过宽而显得很怪。

  • 功能:强制给内容设置一个最大边界,超出部分留白或填充背景。

  • 用法

    dart

    MaxWidthBox(
    maxWidth: 1200, // 无论屏幕多宽,主体内容最宽只展示 1200dp
    background: Container(color: Colors.grey[200]), // 左右两侧留白背景
    child: child!,
    )
MaterialApp(
builder: (context, child) => ResponsiveBreakpoints.builder(
// 1. 最外层:锁定最大宽度,防止 2080px 这种超宽屏导致 UI 散架
child: MaxWidthBox(
maxWidth: 1200, // 无论屏幕多宽,商城内容区最大 1200dp
background: Container(color: const Color(0xFFF5F5F5)), // 屏幕两侧多出的部分背景色
// 2. 中间层:执行镜像缩放,让你不用写 .w
child: ResponsiveScaledBox(
width: 600, // 你的设计稿基准宽度
child: child!, // 这里是具体的页面内容
),
),
// 3. 断点配置:用于代码里判断 isTablet
breakpoints: [
const Breakpoint(start: 0, end: 450, name: MOBILE),
const Breakpoint(start: 451, end: 1200, name: TABLET),
const Breakpoint(start: 1201, end: double.infinity, name: DESKTOP),
],
),
home: const HomeScreen(),
);

3. ResponsiveRowColumn (行列自动转换)

Section titled “3. ResponsiveRowColumn (行列自动转换)”

这是针对商城 App 详情页的神器。它可以根据断点自动切换 横向 (Row)纵向 (Column) 排列。

  • 场景:手机上是“上图下文”,Pad 上自动变成“左图右文”。

  • 优势:不需要写两个 Widget,只需包裹一层。

  • 写法

    dart

    ResponsiveRowColumn(
    // 核心逻辑:手机返回 COLUMN,Pad 返回 ROW
    layout: ResponsiveBreakpoints.of(context).isMobile
    ? ResponsiveRowColumnType.COLUMN
    : ResponsiveRowColumnType.ROW,
    // 间距设置:Row 时水平间距 20,Column 时垂直间距 20
    columnSpacing: 20,
    rowSpacing: 20,
    // 决定这里横着排还是竖着排
    children: [
    // 左侧/上侧:商品大图
    ResponsiveRowColumnItem(
    rowFlex: 2, // 在 Pad 上占 2 份宽度
    child: Image.asset('assets/product.png', fit: BoxFit.cover),
    ),
    // 右侧/下侧:商品标题和价格
    ResponsiveRowColumnItem(
    rowFlex: 3, // 在 Pad 上占 3 份宽度
    child: Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
    Text("2026 新款超轻跑步鞋", style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
    SizedBox(height: 10),
    Text("¥599.00", style: TextStyle(color: Colors.red, fontSize: 20)),
    ],
    ),
    ),
    ],
    )

它增强了原生的 GridView,让你可以针对不同断点直接配置间距和对齐方式。

  • 功能:在不同设备上自动调整固定间距和自适应列数,配合 ScaledBox 使用时,能产生极其稳定的宫格效果。
  • 2026 年的高级进阶:Banned/Clamping (缩放限制)

在全局缩放模式下,如果你担心在某些极小或极大的屏幕上缩放得太离谱:

  • 功能:可以设置缩放的“上下限”。
  • 作用:比如设置最小缩放不低于 0.8 倍,最大不超过 1.5 倍,防止 UI 元素在 2080px 屏幕上大到像桌面图标。
lib/features/home/presentation/screens/home_screen_m.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:responsive_framework/responsive_framework.dart';
import '../providers/home_controller.dart'; // 引入你的控制器
class HomeProductGrid extends ConsumerWidget {
const HomeProductGrid({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
// 1. 获取 Controller 中的商品数据状态
final productState = ref.watch(homeControllerProvider);
// 2. 根据状态渲染 UI
return productState.when(
data: (products) => ResponsiveGridView.builder(
// 这里就是你写的那个组件
gridDelegate: const ResponsiveGridDelegate(
maxExtent: 200,
mainAxisSpacing: 16,
crossAxisSpacing: 16,
childAspectRatio: 0.8,
),
itemCount: products.length,
padding: const EdgeInsets.all(16),
itemBuilder: (context, index) {
final product = products[index];
return ProductCard(product: product); // 渲染单个商品卡片
},
),
loading: () => const Center(child: CircularProgressIndicator()),
error: (err, stack) => Center(child: Text('加载失败: $err')),
);
}
}

原因就在这里,不是你错觉,我刚查了你那两个包的真实配置:

  • 你的 uniapp 包:targetSdk=28
  • 你的 Flutter 包:targetSdk=36

这会导致系统行为完全不同。

在 Android 16(API 36)+ 大屏设备(平板)上,系统会对 screenOrientation / setRequestedOrientation 做“自适配优先”处理,很多情况下不会按老规则强锁方向。

  • 在大屏设备(你这个 Pixel Tablet 属于)上,系统会默认放宽/忽略方向限制

targetSdk=28 的旧应用还走老兼容路径,所以看起来“uniapp 能锁,Flutter 不能锁”。

一句话:不是 uniapp 天生更能锁,是它 targetSdk 更低,绕开了 Android 16 新规则。

你现在有两个可行方案:

  • 临时稳定方案:把 Flutter 的 targetSdk 降到 35(你刚才也同意可考虑),旋转锁会恢复老行为
  • 长期方案:按 Android 16 的大屏自适配规范改 UI,不再依赖强锁方向

如果你要,我下一步就直接把项目改成 targetSdk=35 并帮你重装验证。