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

如何通过ScrollController实现向下滚动隐藏CustomNavigationBarItem、向上滚动显示

解决Flutter滚动时显示/隐藏CustomNavigationBar的问题

看起来你遇到的核心问题是ScrollController没有绑定到正确的可滚动组件上——你现在把控制器挂在了横向滚动的PageView上,但你需要监听的是每个页面内部的纵向滚动事件(比如DashBoardScreen里的ListView/SingleChildScrollView),所以导航栏的显示/隐藏逻辑根本没被触发。

下面是具体的修复方案和优化后的代码:

步骤1:将ScrollController传递给子页面的可滚动组件

首先,你需要让每个子页面(比如DashBoardScreen、IPetCatScreen等)支持接收ScrollController参数,然后在它们内部的可滚动组件(比如ListView)上绑定这个控制器。

以DashBoardScreen为例,修改它的构造函数:

class DashBoardScreen extends StatelessWidget {
  final ScrollController scrollController;
  
  const DashBoardScreen({Key? key, required this.scrollController}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListView(
      controller: scrollController, // 绑定控制器
      children: [
        // 你的页面内容
      ],
    );
  }
}

其他页面也做同样的修改,确保它们的可滚动组件都使用这个控制器。

步骤2:修复ScrollController的监听逻辑

优化监听逻辑,避免重复触发setState,同时增加边缘判断防止误操作:

@override
void initState() {
  super.initState();
  pageController = PageController(initialPage: _currentIndex, keepPage: true);
  _isVisible = true;
  _hideButtonController = ScrollController();
  
  _hideButtonController.addListener(() {
    // 滚动方向向下(reverse是用户手指向下滑,页面向上滚)
    if (_hideButtonController.position.userScrollDirection == ScrollDirection.reverse) {
      if (_isVisible && !_hideButtonController.position.atEdge) {
        setState(() => _isVisible = false);
      }
    } 
    // 滚动方向向上(forward是用户手指向上滑,页面向下滚)
    else if (_hideButtonController.position.userScrollDirection == ScrollDirection.forward) {
      if (!_isVisible && !_hideButtonController.position.atEdge) {
        setState(() => _isVisible = true);
      }
    }
  });
}

步骤3:优化导航栏的动画效果

你之前用AnimatedContainer修改height的方式容易导致布局跳动,换成AnimatedOpacity + Transform.translate的组合,过渡会更流畅:

Widget _buildBlurEffect() {
  return AnimatedOpacity(
    duration: const Duration(milliseconds: 300),
    opacity: _isVisible ? 1 : 0,
    child: Transform.translate(
      offset: Offset(0, _isVisible ? 0 : 100), // 向下移出屏幕
      duration: const Duration(milliseconds: 300),
      child: CustomNavigationBar(
        iconSize: 30.0,
        selectedColor: Colors.white,
        strokeColor: Colors.white12,
        unSelectedColor: Colors.grey[600],
        backgroundColor: AppTheme.nearlyBlack,
        borderRadius: const Radius.circular(20.0),
        blurEffect: true,
        opacity: 0.8,
        items: const [
          CustomNavigationBarItem(icon: FaIcon(FontAwesomeIcons.paw)),
          CustomNavigationBarItem(icon: FaIcon(FontAwesomeIcons.filter)),
          CustomNavigationBarItem(icon: FaIcon(FontAwesomeIcons.heart)),
          CustomNavigationBarItem(icon: FaIcon(FontAwesomeIcons.shoppingBasket)),
          CustomNavigationBarItem(icon: FaIcon(FontAwesomeIcons.userAlt)),
        ],
        currentIndex: _currentIndex,
        onTap: (index) {
          setState(() {
            _currentIndex = index;
            pageController.animateToPage(
              _currentIndex,
              duration: const Duration(milliseconds: 500),
              curve: Curves.linear,
            );
          });
        },
        isFloating: true,
      ),
    ),
  );
}

步骤4:在PageView中传递控制器给子页面

修改buildPageView方法,把_hideButtonController传递给每个子页面:

Widget buildPageView() {
  return PageView(
    key: orderFormKey,
    controller: pageController,
    onPageChanged: pageChanged,
    children: <Widget>[
      DashBoardScreen(scrollController: _hideButtonController),
      IPetCatScreen(scrollController: _hideButtonController),
      CreateCartScreen(scrollController: _hideButtonController),
      CartScreen(scrollController: _hideButtonController),
      IPetSettingsScreen(scrollController: _hideButtonController),
    ],
  );
}

关键说明

  • 为什么要绑定到子页面的滚动组件?因为PageView的滚动是横向的,而你需要监听的是页面内部的纵向滚动事件,只有把控制器挂在纵向滚动的组件上,才能正确捕捉到滚动方向。
  • 动画优化:用Transform.translate配合AnimatedOpacity,既实现了隐藏时的位移效果,又保证了透明度平滑过渡,比直接修改height更自然。
  • 边缘判断:增加atEdge判断,避免用户滚动到页面顶部/底部时,误触发导航栏的显示/隐藏。

内容的提问来源于stack exchange,提问作者Mahmoud Al-Haroon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 03:22:30