You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何根据内容调整Widget大小?DraggableScrollableSheet适配问题

实现DraggableScrollableSheet自动适配内容高度

要让DraggableScrollableSheet根据内容(包括Visibility组件的显隐)自动调整尺寸,核心是让Sheet能感知内容的实际高度,并动态调整自身的尺寸参数,同时确保不可见的Visibility组件不占用空间。

关键要点

  • 确保Visibility组件的maintainSize设为false(默认值,不可见时完全不占空间)
  • 使用GlobalKey获取内容容器的实际高度,动态更新Sheet的尺寸参数
  • 结合SingleChildScrollView处理内容超出视口的情况(可选,当内容高度超过屏幕时允许滚动)

完整代码示例

import 'package:flutter/material.dart';

class AutoSizeSheetDemo extends StatefulWidget {
  const AutoSizeSheetDemo({super.key});

  @override
  State<AutoSizeSheetDemo> createState() => _AutoSizeSheetDemoState();
}

class _AutoSizeSheetDemoState extends State<AutoSizeSheetDemo> {
  // 用于获取内容容器的实际高度
  final GlobalKey _contentKey = GlobalKey();
  bool _showExtraWidgets = false;
  double _sheetMinSize = 0.2;
  double _sheetMaxSize = 0.5;

  @override
  void initState() {
    super.initState();
    // 初始获取一次内容高度
    WidgetsBinding.instance.addPostFrameCallback((_) => _updateSheetSize());
  }

  void _updateSheetSize() {
    final RenderBox? renderBox =
        _contentKey.currentContext?.findRenderObject() as RenderBox?;
    if (renderBox == null) return;

    final screenHeight = MediaQuery.of(context).size.height;
    final contentHeight = renderBox.size.height;
    final newSize = contentHeight / screenHeight;

    setState(() {
      // 确保尺寸在0.1到1.0之间(DraggableScrollableSheet的有效范围)
      _sheetMinSize = newSize.clamp(0.1, 1.0);
      _sheetMaxSize = newSize.clamp(0.1, 1.0);
      // 如果需要允许拖动调整,可将maxSize设为1.0,minSize设为计算出的最小高度
      // _sheetMaxSize = 1.0;
    });
  }

  void _toggleWidgets() {
    setState(() {
      _showExtraWidgets = !_showExtraWidgets;
    });
    // 内容变化后延迟更新尺寸,确保布局完成
    WidgetsBinding.instance.addPostFrameCallback((_) => _updateSheetSize());
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("自动适配Sheet")),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            showModalBottomSheet(
              context: context,
              isScrollControlled: true,
              builder: (context) {
                return DraggableScrollableSheet(
                  initialChildSize: _sheetMinSize,
                  minChildSize: _sheetMinSize,
                  maxChildSize: _sheetMaxSize,
                  builder: (context, scrollController) {
                    return SingleChildScrollView(
                      controller: scrollController,
                      child: Container(
                        key: _contentKey,
                        padding: const EdgeInsets.all(16),
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            // 固定显示的Widget 1
                            const Text(
                              "固定内容1",
                              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                            ),
                            const SizedBox(height: 16),
                            // 固定显示的Widget 2
                            Container(
                              height: 80,
                              color: Colors.blue[100],
                              child: const Center(child: Text("固定容器")),
                            ),
                            const SizedBox(height: 16),
                            // 可切换显示的Widget 3
                            Visibility(
                              visible: _showExtraWidgets,
                              // 确保不可见时不占空间
                              maintainSize: false,
                              maintainAnimation: false,
                              maintainState: false,
                              child: Column(
                                children: [
                                  const Text("可显示/隐藏内容1"),
                                  const SizedBox(height: 16),
                                  Container(
                                    height: 120,
                                    color: Colors.green[100],
                                    child: const Center(child: Text("动态容器1")),
                                  ),
                                ],
                              ),
                            ),
                            const SizedBox(height: 16),
                            // 可切换显示的Widget 4
                            Visibility(
                              visible: _showExtraWidgets,
                              maintainSize: false,
                              child: Column(
                                children: [
                                  const Text("可显示/隐藏内容2"),
                                  const SizedBox(height: 16),
                                  Container(
                                    height: 100,
                                    color: Colors.orange[100],
                                    child: const Center(child: Text("动态容器2")),
                                  ),
                                ],
                              ),
                            ),
                            const SizedBox(height: 16),
                            // 切换按钮
                            ElevatedButton(
                              onPressed: _toggleWidgets,
                              child: Text(_showExtraWidgets ? "隐藏额外内容" : "显示额外内容"),
                            ),
                          ],
                        ),
                      ),
                    );
                  },
                );
              },
            );
          },
          child: const Text("打开Sheet"),
        ),
      ),
    );
  }
}

代码说明

  1. GlobalKey获取内容高度:通过_contentKey获取内容容器的RenderBox,计算其高度与屏幕高度的比例,作为Sheet的尺寸参数。
  2. Visibility配置:显式设置maintainSize: false,确保不可见时不占用布局空间。
  3. 动态更新尺寸:每次切换Visibility状态后,通过addPostFrameCallback等待布局完成,再更新Sheet的minChildSize和maxChildSize。
  4. 滚动处理:用SingleChildScrollView包裹内容,当内容高度超过Sheet的最大尺寸时(如果将maxChildSize设为1.0),允许用户滚动查看全部内容。

如果你希望Sheet仍可拖动调整大小,可以将_sheetMaxSize设为1.0,这样最小尺寸是内容高度,最大尺寸占满屏幕,用户可以在两者之间拖动。

内容的提问来源于stack exchange,提问作者Milan Gaur

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 16:03:37