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

如何在Flutter中实现带底层可见效果的堆叠式Bottom Sheet?

实现堆叠式Bottom Sheet的解决方案

不用showModalBottomSheet(它会全屏覆盖底层内容),改用Scaffold内置的showBottomSheet方法,它支持在Scaffold的overlay层叠加多个sheet,且能轻松控制每个sheet的高度,实现底层sheet部分可见的效果。

完整代码示例

import 'package:flutter/material.dart';

void main() => runApp(const StackedBottomSheetApp());

class StackedBottomSheetApp extends StatelessWidget {
  const StackedBottomSheetApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('堆叠式Bottom Sheet示例')),
        body: Center(
          child: ElevatedButton(
            onPressed: () => _showFirstBottomSheet(context),
            child: const Text('打开第一个Bottom Sheet'),
          ),
        ),
      ),
    );
  }

  void _showFirstBottomSheet(BuildContext context) {
    final sheetController = Scaffold.of(context).showBottomSheet(
      (context) => Container(
        height: MediaQuery.of(context).size.height * 0.7,
        decoration: const BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
        ),
        child: Column(
          children: [
            const Padding(
              padding: EdgeInsets.all(16.0),
              child: Text(
                '第一个Bottom Sheet',
                style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
              ),
            ),
            Expanded(
              child: ListView.builder(
                itemCount: 5,
                itemBuilder: (context, index) => ListTile(
                  title: Text('条目 ${index + 1}'),
                  leading: const Icon(Icons.list),
                ),
              ),
            ),
            Padding(
              padding: const EdgeInsets.all(16.0),
              child: ElevatedButton(
                onPressed: () => _showSecondBottomSheet(context),
                child: const Text('打开第二个Bottom Sheet'),
              ),
            ),
          ],
        ),
      ),
    );
    // 可选:监听第一个sheet的关闭事件
    sheetController.closed.then((_) => print('第一个sheet已关闭'));
  }

  void _showSecondBottomSheet(BuildContext context) {
    final sheetController = Scaffold.of(context).showBottomSheet(
      (context) => Container(
        height: MediaQuery.of(context).size.height * 0.6,
        decoration: const BoxDecoration(
          color: Colors.white,
          borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
        ),
        child: Column(
          children: [
            const Padding(
              padding: EdgeInsets.all(16.0),
              child: Text(
                '第二个Bottom Sheet',
                style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
              ),
            ),
            Expanded(
              child: Center(
                child: ElevatedButton(
                  onPressed: () => Navigator.of(context).pop(),
                  child: const Text('关闭当前Sheet'),
                ),
              ),
            ),
          ],
        ),
      ),
    );
    sheetController.closed.then((_) => print('第二个sheet已关闭'));
  }
}

关键说明

  • 叠加原理:showBottomSheet会将sheet添加到Scaffold的Overlay层,后续弹出的sheet会位于之前的sheet上方。
  • 可见控制:通过设置第二个sheet的高度(0.6倍屏幕高度)小于第一个sheet的高度(0.7倍屏幕高度),让第一个sheet的底部区域保持可见。
  • 交互优化:每个sheet都可以通过Navigator.of(context).pop()单独关闭,也可以通过返回的PersistentBottomSheetController监听关闭事件或主动关闭。

进阶方案(如需拖拽调整)

如果需要支持拖拽调整sheet高度,可以结合DraggableScrollableSheet和Stack组件,手动管理多个sheet的堆叠层级和高度,代码示例如下:

// 简化的拖拽式堆叠sheet示例
void _showDraggableStackedSheets(BuildContext context) {
  showModalBottomSheet(
    context: context,
    isScrollControlled: true,
    builder: (context) => Stack(
      children: [
        // 第一个拖拽sheet
        DraggableScrollableSheet(
          initialChildSize: 0.7,
          minChildSize: 0.3,
          maxChildSize: 0.9,
          builder: (context, scrollController) => Container(
            color: Colors.grey[200],
            child: ListView.builder(
              controller: scrollController,
              itemCount: 10,
              itemBuilder: (context, index) => ListTile(title: Text('条目 $index')),
            ),
          ),
        ),
        // 第二个拖拽sheet(默认覆盖在上方)
        Positioned(
          top: MediaQuery.of(context).size.height * 0.1,
          left: 0,
          right: 0,
          child: DraggableScrollableSheet(
            initialChildSize: 0.6,
            minChildSize: 0.4,
            maxChildSize: 0.8,
            builder: (context, scrollController) => Container(
              color: Colors.white,
              child: Center(child: ElevatedButton(onPressed: () {}, child: const Text('操作'))),
            ),
          ),
        ),
      ],
    ),
  );
}

内容的提问来源于stack exchange,提问作者Ubaidillah Faris Al-Faruq

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 13:32:39