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

如何在NestedScrollView滚动到底部时移除Bottom Sheet组件?

实现滚动到底部移除BottomSheet的方案

要实现滚动到NestedScrollView底部时移除BottomSheet,核心思路是监听滚动位置,判断是否到达底部后,通过状态变量控制BottomSheet的显示/隐藏。

步骤1:添加状态变量管理BottomSheet显示

在你的State类中添加布尔变量,用于控制BottomSheet的显示状态:

bool _showBottomSheet = true;

步骤2:修改BottomSheet的条件渲染

将原有的bottomSheet属性改为根据状态变量动态渲染:

bottomSheet: _showBottomSheet 
    ? Container(
        height: 40,
        width: double.infinity,
        decoration: BoxDecoration(
          gradient: LinearGradient(
            begin: Alignment.topCenter,
            end: FractionalOffset.bottomCenter,
            colors: <Color>[
              Colors.white.withOpacity(0.1),
              Colors.white,
            ],
            stops: [0, 1],
          ),
        ),
      )
    : null,

步骤3:监听滚动事件判断是否到达底部

在buildWidget(context, 'contacts')外层包裹NotificationListener<ScrollNotification>,监听滚动位置并更新状态:

修改后的代码片段:

NotificationListener<ScrollNotification>(
  onNotification: (scrollNotification) {
    // 预留10像素偏移避免滚动精度导致的误判
    if (scrollNotification is ScrollUpdateNotification &&
        scrollNotification.metrics.pixels >= 
        scrollNotification.metrics.maxScrollExtent - 10) {
      if (_showBottomSheet) {
        setState(() {
          _showBottomSheet = false;
        });
      }
    }
    // 如需滚动回顶部时重新显示BottomSheet,可取消以下注释
    // else if (scrollNotification.metrics.pixels <= 100 && !_showBottomSheet) {
    //   setState(() {
    //     _showBottomSheet = true;
    //   });
    // }
    return true;
  },
  child: buildWidget(context, 'contacts'),
)

完整修改后的代码

// 状态变量
bool _showBottomSheet = true;

// ... 其他业务代码 ...

NestedScrollView(
  headerSliverBuilder: (context, isScrolled) {
    return [
      SliverPersistentHeader(
        pinned: true,
        floating: false,
        delegate: ChooseUsersHeaderDelegate(
          widgetList: Container(
            color: Colors.white,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                /// Search Box
                buildSearch(),
              ],
            ),
          ),
          minHeight: selectedContactId.isNotEmpty ? 135 : 60,
          maxHeight: selectedContactId.isNotEmpty ? 135 : 60,
          parentContext: context,
        ),
      ),
    ];
  },
  body: Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      Column(
        mainAxisAlignment: MainAxisAlignment.start,
        children: [
          Text(
            'allContacts',
            style: GoogleFonts.montserrat(
              fontSize: 14,
              fontWeight: FontWeight.w500,
              color: primaryColor,
              fontStyle: FontStyle.normal,
            ),
          ).tr(),
          Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: [
              isLoading
                  ? ReusableLoadingContact()
                  : NotificationListener<OverscrollIndicatorNotification>(
                      onNotification: (overScroll) {
                        overScroll.disallowIndicator();
                        return true;
                      },
                      child: NotificationListener<ScrollNotification>(
                        onNotification: (scrollNotification) {
                          if (scrollNotification is ScrollUpdateNotification &&
                              scrollNotification.metrics.pixels >= 
                              scrollNotification.metrics.maxScrollExtent - 10) {
                            if (_showBottomSheet) {
                              setState(() {
                                _showBottomSheet = false;
                              });
                            }
                          }
                          return true;
                        },
                        child: buildWidget(context, 'contacts'),
                      ),
                    ),
            ],
          ),
        ],
      ),
    ],
  ),
),
bottomSheet: _showBottomSheet 
    ? Container(
        height: 40,
        width: double.infinity,
        decoration: BoxDecoration(
          gradient: LinearGradient(
            begin: Alignment.topCenter,
            end: FractionalOffset.bottomCenter,
            colors: <Color>[
              Colors.white.withOpacity(0.1),
              Colors.white,
            ],
            stops: [0, 1],
          ),
        ),
      )
    : null,

关键说明

  • 滚动判断时预留10像素偏移,避免因滚动精度问题导致频繁触发状态更新。
  • 确保buildWidget返回的是可滚动组件(如ListView、GridView),否则无法触发滚动通知。

内容的提问来源于stack exchange,提问作者Kim San

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 15:50:28