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 最宽 ~440,iPad 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(), ), ], ), ); }, ); }