import 'package:flutter/material.dart'; /// 响应式断点工具:用 [Size.shortestSide] 而非 width 判定窗口尺寸, /// 使手机横屏(1600×900 → shortSide=900)正确落入 medium 档。 /// /// 详见 docs/手机端UI优化方案-v2.md §7.4。 enum AppWindowSize { compact, medium, expanded } class AppResponsive { AppResponsive(this.size, this.orientation); final Size size; final Orientation orientation; factory AppResponsive.of(BuildContext context) => AppResponsive( MediaQuery.sizeOf(context), MediaQuery.orientationOf(context), ); bool get isLandscape => orientation == Orientation.landscape; AppWindowSize get windowSize => switch (size.shortestSide) { < 600 => AppWindowSize.compact, < 840 => AppWindowSize.medium, // ★ 手机横屏 900 落这里 _ => AppWindowSize.expanded, }; /// 横屏且宽度够时启用主从(双栏)布局。 bool get useMasterDetail => size.width >= 840 && isLandscape; /// 自适应网格列数(列表 / 卡片网格)。 int gridCount({double minTileWidth = 320}) => (size.width / minTileWidth).floor().clamp(2, 6); /// 内容最大宽度(限宽居中,避免横屏拉爆)。 double get contentMaxWidth => switch (windowSize) { AppWindowSize.compact => double.infinity, AppWindowSize.medium => 560, AppWindowSize.expanded => 720, }; /// 栅格间距。 double get gutter => switch (windowSize) { AppWindowSize.compact => 12, AppWindowSize.medium => 24, _ => 32, }; /// 卡片内边距(横屏更宽松)。 double get cardPadding => windowSize == AppWindowSize.compact ? 16 : 20; } extension AppResponsiveX on BuildContext { AppResponsive get responsive => AppResponsive.of(this); }