Flutter中如何让showModalBottomSheet实现响应式适配?
解决方案
要实现WebView状态变化时自动调整BottomSheet高度,核心是监听WebView加载状态、获取网页实际高度并动态更新BottomSheet容器高度,具体实现如下:
1. 改用StatefulWidget管理BottomSheet状态
把原BottomSheet组件改为带状态的组件,用于动态更新高度:
class DynamicHeightBottomSheet extends StatefulWidget { const DynamicHeightBottomSheet({super.key}); @override State<DynamicHeightBottomSheet> createState() => _DynamicHeightBottomSheetState(); } class _DynamicHeightBottomSheetState extends State<DynamicHeightBottomSheet> { InAppWebViewController? _webViewController; double _bottomSheetHeight = MediaQuery.of(context).size.height - (kToolbarHeight * 2); // 初始高度 final double _minHeight = 200; // 最小高度限制 @override Widget build(BuildContext context) { return Container( alignment: Alignment.center, height: _bottomSheetHeight, decoration: BoxDecoration( color: lmWhite, borderRadius: BorderRadius.circular(20.r), ), clipBehavior: Clip.hardEdge, child: Stack( children: [ InAppWebView( initialUrlRequest: URLRequest(url: Uri.parse("你的网页地址")), onWebViewCreated: (controller) { _webViewController = controller; }, onLoadStop: (controller, url) async { // 网页加载完成后获取实际滚动高度 final scrollHeight = await controller.getScrollHeight(); if (scrollHeight != null) { setState(() { // 计算适配高度:不超过屏幕可用高度,同时不低于最小高度 final screenAvailableHeight = MediaQuery.of(context).size.height - kToolbarHeight - 20; // 预留顶部间距 _bottomSheetHeight = scrollHeight > screenAvailableHeight ? screenAvailableHeight : scrollHeight > _minHeight ? scrollHeight : _minHeight; }); } }, // 可选:监听网页滚动/内容变化,实时更新高度(按需启用,频繁调用可能影响性能) onScrollChanged: (controller, x, y) async { // final scrollHeight = await controller.getScrollHeight(); // if (scrollHeight != null) { // setState(() { // _bottomSheetHeight = scrollHeight; // }); // } }, ), // 你的Opacity组件示例 Opacity(opacity: 0.5, child: Container(color: Colors.black.withOpacity(0.1))), ], ), ); } }
2. 调整showModalBottomSheet参数
确保isScrollControlled保持为true,让BottomSheet支持动态高度调整:
showModalBottomSheet( enableDrag: false, isDismissible: false, isScrollControlled: true, shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( topRight: Radius.circular(20.r), topLeft: Radius.circular(20.r), ), ), context: context, builder: (context) => const DynamicHeightBottomSheet(), );
关键细节
- 核心逻辑:通过
InAppWebViewController.getScrollHeight()获取网页实际高度,这是实现动态调整的基础。 - 边界控制:设置最小高度避免BottomSheet过矮,同时限制最大高度不超过屏幕可用空间,防止内容溢出。
- 性能考量:优先在
onLoadStop事件中更新高度,如需实时响应内容变化再启用onScrollChanged监听,减少不必要的状态更新。
内容的提问来源于stack exchange,提问作者Shebin PR
相关产品推荐
相关产品推荐

