feat:参照研听的基础工程

This commit is contained in:
jingyun
2026-06-18 15:02:28 +08:00
commit 364fc837b3
367 changed files with 16495 additions and 0 deletions
+86
View File
@@ -0,0 +1,86 @@
import 'dart:math';
import 'package:flutter/widgets.dart';
import '../theme/spacing.dart';
/// iPad 响应式布局:
/// 宽 ≥ [breakpoint] 进入平板布局——屏边距 36、内容列统一限宽 920 居中
/// `padding: max(36, (宽-920)/2)`)、卡片列表两列(列距 18、行内等高)、
/// 底部 tab 行限宽 600 居中。手机布局完全不变。
abstract class Adaptive {
/// 平板断点(iPhone 最宽 ~440iPad 11″ 竖屏 834 起)
static const double breakpoint = 700;
/// 平板屏边距(demo `--pad-screen: 36px`
static const double padTablet = 36;
/// 内容列限宽(demo 所有页统一 920 居中)
static const double contentMaxWidth = 920;
/// 两列列表的列间距(demo `column-gap: 18px`
static const double columnGap = 18;
/// 底部 tab 行限宽(demo `.nav .tabs{max-width:600px}`
static const double tabsMaxWidth = 600;
static bool isTablet(BuildContext context) =>
MediaQuery.sizeOf(context).width >= breakpoint;
/// 屏水平边距:手机 [Spacing.page];平板 `max(36, (宽-920)/2)`
/// 即内容超 920 时左右对称留白实现居中限宽。
static double hPad(BuildContext context) {
final w = MediaQuery.sizeOf(context).width;
if (w < breakpoint) return Spacing.page;
return max(padTablet, (w - contentMaxWidth) / 2);
}
static EdgeInsets screenPadding(
BuildContext context, {
double top = 0,
double bottom = 0,
}) {
final h = hPad(context);
return EdgeInsets.fromLTRB(h, top, h, bottom);
}
}
/// 卡片列表自适应 sliver:手机单列(卡间距 [Spacing.cardGap]);
/// 平板两列——卡片两两成行、行内等高(IntrinsicHeight + stretch
/// 对应 demo CSS grid `1fr 1fr` 的等高行行为)。
SliverList adaptiveCardSliver(
BuildContext context, {
required int itemCount,
required Widget Function(BuildContext, int) itemBuilder,
double rowGap = Spacing.cardGap,
}) {
if (!Adaptive.isTablet(context)) {
return SliverList.separated(
itemCount: itemCount,
separatorBuilder: (_, _) => SizedBox(height: rowGap),
itemBuilder: itemBuilder,
);
}
final rows = (itemCount + 1) ~/ 2;
return SliverList.separated(
itemCount: rows,
separatorBuilder: (_, _) => SizedBox(height: rowGap),
itemBuilder: (c, r) {
final rightIndex = r * 2 + 1;
return IntrinsicHeight(
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(child: itemBuilder(c, r * 2)),
const SizedBox(width: Adaptive.columnGap),
Expanded(
child: rightIndex < itemCount
? itemBuilder(c, rightIndex)
: const SizedBox(),
),
],
),
);
},
);
}