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

Flutter中Drawer切换页面时BottomNavigationBar消失问题求助

问题描述

我希望在所有页面复用NavigationBar组件,BottomNavigationBar在主页面运行正常,但通过Drawer切换页面时该组件会消失。已参考相关教程,但仅主页面显示该组件。我尝试过将NavBar封装为独立StatefulWidget,并复制到需要显示该栏的页面的bottomNavigationBar中,但问题仍未解决。以下是我的主页代码:

import 'package:flutter/material.dart';
import 'package:kikapp/create.dart';
import 'package:kikapp/home.dart';
import 'package:kikapp/zero.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'KikApp',
        theme: ThemeData(
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.grey),
          useMaterial3: true,
        ),
        debugShowCheckedModeBanner: false,
        initialRoute: 'home',
        routes: {
          'home': (context) => const Main(),
          'profile': (context) => const Create(),
          'zero': (context) => const Zero(),
        }
    );
  }
}

//Drawer
class MyDrawer extends StatelessWidget {
  const MyDrawer({super.key});

  @override
  Widget build(BuildContext context) {
    return Drawer(
        child: ListView(
          padding: EdgeInsets.zero,
          children: [
            const DrawerHeader(
              decoration: BoxDecoration(
                color: Colors.black12,
              ),
              child: Text(
                'Anarkika',
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 24,
                ),
              ),
            ),
            ListTile(
              leading: const Icon(Icons.home),
              title: const Text('Home'),
              onTap: () {
                Navigator.pop(context);
                Navigator.of(context).push(
                    MaterialPageRoute(builder: (context) => const Home()));
              },
            ),
            ListTile(
              leading: const Icon(Icons.book),
              title: const Text('Zero'),
              onTap: () {
                Navigator.pop(context);
                Navigator.of(context).push(
                    MaterialPageRoute(builder: (context) => const Zero()));
              },
            ),
            ListTile(
              leading: const Icon(Icons.add),
              title: const Text('Create'),
              onTap: () {
                Navigator.pop(context);
                Navigator.of(context).push(
                    MaterialPageRoute(builder: (context) => const Create()));
              },
            ),
          ],
        ),
      );
  }
}

//Body
class Main extends StatefulWidget {
  const Main({super.key});

  @override
  State<Main> createState() => _MainState();
}

class _MainState extends State<Main> {
  int index = 0;
  final pages = [
    const Home(),
    const Zero(),
    const Create(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: pages[index],
      bottomNavigationBar: NavigationBar(
        height: 70,
        animationDuration: const Duration(milliseconds: 1000),
        labelBehavior: NavigationDestinationLabelBehavior.onlyShowSelected,
        backgroundColor: Colors.grey,
        indicatorColor: Colors.white,
        selectedIndex: index,
        onDestinationSelected: (index) => setState(() => this.index = index),
        destinations: const [
          NavigationDestination(icon: Icon(Icons.home_outlined), selectedIcon: Icon(Icons.home), label: 'Home',),
          NavigationDestination(icon: Icon(Icons.book_outlined), selectedIcon: Icon(Icons.book), label: 'Zero',),
          NavigationDestination(icon: Icon(Icons.add_outlined), selectedIcon: Icon(Icons.add), label: 'Create',),
        ],
      ),
    );
  }
}

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

  @override
  State<Nav> createState() => _NavState();
}

class _NavState extends State<Nav> {
   int index = 0;
  final pages = [
    const Home(),
    const Zero(),
    const Create(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      bottomNavigationBar: NavigationBar(
        animationDuration: const Duration(milliseconds: 1500),
        labelBehavior: NavigationDestinationLabelBehavior.onlyShowSelected,
        backgroundColor: Colors.grey,
        indicatorColor: Colors.white,
        selectedIndex: index,
        onDestinationSelected: (index) => setState(() => this.index = index),
        destinations: const [
          NavigationDestination(icon: Icon(Icons.home_outlined), selectedIcon: Icon(Icons.home), label: 'Home',),
          NavigationDestination(icon: Icon(Icons.book_outlined), selectedIcon: Icon(Icons.book), label: 'Zero',),
          NavigationDestination(icon: Icon(Icons.add_outlined), selectedIcon: Icon(Icons.add), label: 'Create',),
        ],
      ),
    );
  }
}
问题原因

核心问题是Drawer切换页面时,你直接push了独立的页面组件(如Home、Zero、Create),这些组件本身没有包裹在带有BottomNavigationBar的Scaffold中。而主页面Main是通过切换body内容来展示不同页面,BottomNavigationBar属于Main的Scaffold,所以主页正常;但Drawer跳转时绕过了Main的结构,直接打开了无底部导航的页面。

解决方案

1. 统一页面容器,所有页面都在Main的body中切换

修改Drawer的跳转逻辑,不要直接push新页面,而是通知Main页面切换当前展示的index,始终保持Main的Scaffold作为容器:

修改MyDrawer组件,添加页面切换回调

class MyDrawer extends StatelessWidget {
  final Function(int) onPageSelected;
  const MyDrawer({super.key, required this.onPageSelected});

  @override
  Widget build(BuildContext context) {
    return Drawer(
      child: ListView(
        padding: EdgeInsets.zero,
        children: [
          const DrawerHeader(
            decoration: BoxDecoration(
              color: Colors.black12,
            ),
            child: Text(
              'Anarkika',
              style: TextStyle(
                color: Colors.white,
                fontSize: 24,
              ),
            ),
          ),
          ListTile(
            leading: const Icon(Icons.home),
            title: const Text('Home'),
            onTap: () {
              Navigator.pop(context);
              onPageSelected(0);
            },
          ),
          ListTile(
            leading: const Icon(Icons.book),
            title: const Text('Zero'),
            onTap: () {
              Navigator.pop(context);
              onPageSelected(1);
            },
          ),
          ListTile(
            leading: const Icon(Icons.add),
            title: const Text('Create'),
            onTap: () {
              Navigator.pop(context);
              onPageSelected(2);
            },
          ),
        ],
      ),
    );
  }
}

修改Main页面,添加Drawer并处理切换回调

class _MainState extends State<Main> {
  int index = 0;
  final pages = [
    const Home(),
    const Zero(),
    const Create(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: Builder(
          builder: (context) => IconButton(
            icon: const Icon(Icons.menu),
            onPressed: () => Scaffold.of(context).openDrawer(),
          ),
        ),
      ),
      drawer: MyDrawer(onPageSelected: (selectedIndex) {
        setState(() {
          index = selectedIndex;
        });
      }),
      body: pages[index],
      bottomNavigationBar: NavigationBar(
        height: 70,
        animationDuration: const Duration(milliseconds: 1000),
        labelBehavior: NavigationDestinationLabelBehavior.onlyShowSelected,
        backgroundColor: Colors.grey,
        indicatorColor: Colors.white,
        selectedIndex: index,
        onDestinationSelected: (index) => setState(() => this.index = index),
        destinations: const [
          NavigationDestination(icon: Icon(Icons.home_outlined), selectedIcon: Icon(Icons.home), label: 'Home',),
          NavigationDestination(icon: Icon(Icons.book_outlined), selectedIcon: Icon(Icons.book), label: 'Zero',),
          NavigationDestination(icon: Icon(Icons.add_outlined), selectedIcon: Icon(Icons.add), label: 'Create',),
        ],
      ),
    );
  }
}

2. 简化路由配置

移除routes中指向单独页面的配置,统一指向Main即可:

routes: {
  '/': (context) => const Main(),
},
initialRoute: '/',

3. 删除多余的Nav组件

Nav组件无需单独封装,Main已经承担了容器和底部导航的管理角色,所有页面切换都在Main内部完成,BottomNavigationBar只需要维护一份。

这样修改后,无论是通过BottomNavigationBar还是Drawer切换页面,都会在Main的Scaffold中切换body内容,BottomNavigationBar会始终显示在页面底部。

内容的提问来源于stack exchange,提问作者Dudu Sandoval Gamarra

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 19:04:51