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

Flutter:打开Drawer时隐藏BottomNavigationBar的实现疑问

解决方案

核心思路是监听首页Drawer的打开/关闭状态,动态控制底部导航栏的显示与隐藏,完全保留你现有多页面状态保存的结构,同时只在首页显示汉堡图标。

步骤1:修改父页面状态类,添加控制变量与全局Key

在承载底部导航栏的_HomePageState中,新增状态控制变量和Drawer全局Key:

bool _isBottomBarVisible = true;
final GlobalKey<DrawerControllerState> _drawerKey = GlobalKey();

步骤2:监听Drawer状态变化

在initState中添加监听器,实时感知Drawer的开闭状态并更新底部导航栏显示状态:

@override
void initState() {
  super.initState();
  // 延迟执行确保Drawer已完成初始化
  WidgetsBinding.instance.addPostFrameCallback((_) {
    _drawerKey.currentState?.addListener(() {
      setState(() {
        _isBottomBarVisible = !_drawerKey.currentState!.isOpen;
      });
    });
  });
}

步骤3:给首页Drawer绑定全局Key

修改Page组件的构造函数,新增drawerKey参数,用于给首页的Drawer绑定全局Key:

class Page extends StatelessWidget {
  const Page({
    Key? key,
    required this.title,
    required this.drawer,
    this.drawerKey, // 新增参数
  }) : super(key: key);
  final String title;
  final bool drawer;
  final GlobalKey<DrawerControllerState>? drawerKey; // 新增变量

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      endDrawer: drawer ? Drawer(key: drawerKey) : null, // 绑定Key
      body: Center(
        child: Text(
          title,
          style: const TextStyle(
            fontSize: 45,
            fontWeight: FontWeight.w500,
          ),
        ),
      ),
    );
  }
}

步骤4:动态控制底部导航栏显示

用AnimatedOpacity+Visibility包裹底部导航栏,实现平滑的显示/隐藏动画:

bottomNavigationBar: AnimatedOpacity(
  opacity: _isBottomBarVisible ? 1.0 : 0.0,
  duration: const Duration(milliseconds: 200),
  child: Visibility(
    visible: _isBottomBarVisible,
    child: Container(
      color: Theme.of(context).primaryColor,
      height: 60,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: [
          IconButton(
            onPressed: () {
              setState(() {
                pageIndex = 0;
              });
            },
            icon: const Icon(Icons.home_outlined),
          ),
          IconButton(
            onPressed: () {
              setState(() {
                pageIndex = 1;
              });
            },
            icon: const Icon(Icons.work_outline_outlined),
          ),
          IconButton(
            onPressed: () {
              setState(() {
                pageIndex = 2;
              });
            },
            icon: const Icon(Icons.widgets_outlined),
          ),
        ],
      ),
    ),
  ),
),

完整修改后的可复现代码

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int pageIndex = 0;
  bool _isBottomBarVisible = true;
  final GlobalKey<DrawerControllerState> _drawerKey = GlobalKey();

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _drawerKey.currentState?.addListener(() {
        setState(() {
          _isBottomBarVisible = !_drawerKey.currentState!.isOpen;
        });
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // 用IndexedStack保存页面状态,和原逻辑一致
      body: IndexedStack(
        index: pageIndex,
        children: [
          Page(
            title: "page 1",
            drawer: true,
            drawerKey: _drawerKey,
          ),
          const Page(title: "page 2", drawer: false),
          const Page(title: "page 3", drawer: false),
        ],
      ),
      bottomNavigationBar: AnimatedOpacity(
        opacity: _isBottomBarVisible ? 1.0 : 0.0,
        duration: const Duration(milliseconds: 200),
        child: Visibility(
          visible: _isBottomBarVisible,
          child: Container(
            color: Theme.of(context).primaryColor,
            height: 60,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                IconButton(
                  onPressed: () {
                    setState(() {
                      pageIndex = 0;
                    });
                  },
                  icon: const Icon(Icons.home_outlined),
                ),
                IconButton(
                  onPressed: () {
                    setState(() {
                      pageIndex = 1;
                    });
                  },
                  icon: const Icon(Icons.work_outline_outlined),
                ),
                IconButton(
                  onPressed: () {
                    setState(() {
                      pageIndex = 2;
                    });
                  },
                  icon: const Icon(Icons.widgets_outlined),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class Page extends StatelessWidget {
  const Page({
    Key? key,
    required this.title,
    required this.drawer,
    this.drawerKey,
  }) : super(key: key);
  final String title;
  final bool drawer;
  final GlobalKey<DrawerControllerState>? drawerKey;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      endDrawer: drawer ? Drawer(key: drawerKey) : null,
      body: Center(
        child: Text(
          title,
          style: const TextStyle(
            fontSize: 45,
            fontWeight: FontWeight.w500,
          ),
        ),
      ),
    );
  }
}

额外说明

  • 用IndexedStack替代直接的pages[pageIndex],可以更好地保存每个页面的状态,和你原有的多导航器逻辑完全兼容。
  • 动画效果用AnimatedOpacity+Visibility组合,既保证隐藏时不占用布局空间,又有平滑的过渡动画,实现成本低且效果自然。
  • 仅首页绑定了Drawer的全局Key,其他页面不受影响,完全符合你“只在首页显示汉堡图标”的需求。

内容的提问来源于stack exchange,提问作者Davinci Cake

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 04:15:57