Files
CloudHome-Ops/lib/widgets/app_bottom_sheet.dart

76 lines
2.3 KiB
Dart
Raw Permalink Normal View History

import 'package:flutter/material.dart';
import '../app/theme.dart';
/// 统一底部弹窗封装:一次性解决「无把手 / 无安全区 / 无限高 / 保存按钮埋在滚动区」。
///
/// - 顶部拖拽把手([BottomSheetThemeData.showDragHandle] 已全局兜底,这里显式再设一次)。
/// - 安全区(不被手势条遮挡)。
/// - 限宽 640 居中(横屏不铺满)。
/// - [footer] 吸底操作栏始终可见,[body] 内部独立滚动。
///
/// 详见 docs/手机端UI优化方案-v2.md §8.4。
Future<T?> showAppBottomSheet<T>({
required BuildContext context,
required Widget body,
Widget? footer,
String? title,
double heightFactor = 0.92,
}) {
return showModalBottomSheet<T>(
context: context,
isScrollControlled: true,
showDragHandle: true,
useSafeArea: true,
constraints: BoxConstraints(
maxWidth: 640,
maxHeight: MediaQuery.sizeOf(context).height * heightFactor,
),
builder: (ctx) => Column(
mainAxisSize: MainAxisSize.min,
children: [
if (title != null)
Padding(
padding: const EdgeInsets.fromLTRB(20, 4, 20, 12),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
title,
style: Theme.of(ctx)
.textTheme
.titleLarge
?.copyWith(fontWeight: FontWeight.bold),
),
),
),
Flexible(
child: SingleChildScrollView(
padding: EdgeInsets.fromLTRB(
20,
0,
20,
20 + MediaQuery.viewInsetsOf(ctx).bottom,
),
child: body,
),
),
if (footer != null)
Container(
decoration: BoxDecoration(
color: Theme.of(ctx).colorScheme.surface,
border: Border(
top: BorderSide(
color: Theme.of(ctx).colorScheme.outlineVariant,
),
),
boxShadow: AppShadows.lg,
),
padding: const EdgeInsets.fromLTRB(20, 12, 20, 12),
// 吸底栏不受滚动影响,但底部手势条区域交给 SafeArea 处理。
child: SafeArea(top: false, child: footer),
),
],
),
);
}