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

如何在切换Drawer时显示Bottom Navigation Bar(仿Discord效果)

实现Drawer切换时显示Bottom Navigation Bar(Discord风格)

要实现类似Discord的效果——仅在Drawer展开时显示Bottom Navigation Bar,核心思路是通过监听Drawer的打开/关闭状态,动态控制BottomNavBar的渲染。以下是具体实现步骤:

1. 父页面状态管理

在承载Drawer和BottomNavBar的父页面(比如HomePage)中,通过状态变量标记Drawer的展开状态,并监听Drawer的动画变化来更新这个变量:

import 'package:flutter/material.dart';
import 'BottomNavBar.dart';
import 'Drawer.dart';

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
  late AnimationController _drawerAnimationController;
  bool _showBottomNavBar = false;

  @override
  void initState() {
    super.initState();
    _drawerAnimationController = AnimationController(vsync: this);
    // 页面渲染完成后获取Drawer的动画控制器
    WidgetsBinding.instance.addPostFrameCallback((_) {
      final drawerController = DrawerController.of(context);
      if (drawerController != null) {
        _drawerAnimationController = drawerController.animationController;
        // 监听动画值变化,更新BottomNavBar显示状态
        _drawerAnimationController.addListener(_updateBottomNavBarVisibility);
      }
    });
  }

  void _updateBottomNavBarVisibility() {
    // 当Drawer动画值大于0.1时(表示正在打开或已打开),显示BottomNavBar
    setState(() {
      _showBottomNavBar = _drawerAnimationController.value > 0.1;
    });
  }

  @override
  void dispose() {
    _drawerAnimationController.removeListener(_updateBottomNavBarVisibility);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Discord风格演示")),
      drawer: const NavigationDrawer(),
      body: const Center(child: Text("主内容区域")),
      // 根据状态动态渲染BottomNavBar
      bottomNavigationBar: _showBottomNavBar ? const BottomNavBar() : null,
    );
  }
}

2. 修正Drawer组件的语法错误

你的Drawer.dart中存在语法问题,以下是修正后的完整代码(补充了示例内容):

import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    Widget buildHeader(BuildContext context) => Material(
          color: Colors.blueGrey,
          child: Padding(
            padding: EdgeInsets.only(
              top: MediaQuery.of(context).padding.top + 20,
              bottom: 20,
            ),
            child: const Column(
              children: [
                CircleAvatar(radius: 40, child: Icon(Icons.person)),
                SizedBox(height: 10),
                Text(
                  "用户名",
                  style: TextStyle(color: Colors.white, fontSize: 18),
                ),
              ],
            ),
          ),
        );

    Widget buildMenuItems(BuildContext context) => Container(
          padding: const EdgeInsets.all(16),
          child: Wrap(
            children: [
              ListTile(
                leading: const Icon(Icons.home),
                title: const Text("首页"),
                onTap: () => Navigator.pop(context),
              ),
              ListTile(
                leading: const Icon(Icons.settings),
                title: const Text("设置"),
                onTap: () => Navigator.pop(context),
              ),
            ],
          ),
        );

    return SingleChildScrollView(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
          buildHeader(context),
          buildMenuItems(context),
        ],
      ),
    );
  }
}

3. 工作原理说明

  • 通过DrawerController.of(context)获取Drawer的动画控制器,监听其动画值变化。动画值范围是0(完全关闭)到1(完全打开),我们设置阈值0.1来判断Drawer是否处于展开状态。
  • 父页面的_showBottomNavBar状态变量控制Scaffold的bottomNavigationBar参数:为BottomNavBar组件时显示,为null时隐藏。
  • 这种方式能覆盖所有Drawer的打开/关闭场景,包括点击菜单按钮、点击遮罩层、返回键关闭等。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 11:50:44