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

Flutter中使用BottomNavigationBar切换屏幕时消除页面堆叠的方法

问题根源

你的问题出在Dashboard页面的结构设计:你在Dashboard的Scaffold body里用Stack同时渲染了pages.elementAt(activeIndex)和Dashboard专属的头部/内容区域。这意味着当切换到其他页面(比如HomePage)时,Dashboard的头部UI并没有被移除,而是和目标页面的内容叠加显示,导致两个AppBar/页面内容同时出现。

解决方案:重构页面结构

核心思路是让每个页面独立,主页面(带BottomNavigationBar的容器)直接根据activeIndex渲染对应页面,而非在Dashboard里嵌套整个页面列表。

步骤1:调整主页面(带BottomNavigationBar的容器)

让主页面直接承载导航逻辑,body区域仅渲染当前选中的页面:

class MainNavigationScreen extends StatefulWidget {
  const MainNavigationScreen({super.key});

  @override
  State<MainNavigationScreen> createState() => _MainNavigationScreenState();
}

class _MainNavigationScreenState extends State<MainNavigationScreen> {
  int activeIndex = 0;

  final List<Widget> pages = const [
    Dashboard(),
    HomePage(checklistData: [], numberofForms: 0, userData: {},),
    ScannerPage(title: 'Scan QR Code',),
    Notifications(),
    Login(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: pages[activeIndex], // 直接渲染当前选中的页面,无嵌套
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: activeIndex,
        onTap: (index) {
          setState(() {
            activeIndex = index;
          });
        },
        // 你的导航项配置
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.dashboard), label: 'Dashboard'),
          BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
          BottomNavigationBarItem(icon: Icon(Icons.qr_code_scanner), label: 'Scanner'),
          BottomNavigationBarItem(icon: Icon(Icons.notifications), label: 'Notifications'),
          BottomNavigationBarItem(icon: Icon(Icons.login), label: 'Login'),
        ],
      ),
    );
  }
}

步骤2:修改Dashboard页面,移除嵌套逻辑

让Dashboard仅展示自己的专属内容,不再嵌套其他页面:

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Constants.primaryColor,
      body: SingleChildScrollView(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const SizedBox(height: kToolbarHeight),
            Container(
              padding: const EdgeInsets.symmetric(horizontal: 16.0),
              child: Column(
                mainAxisSize: MainAxisSize.min,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  GestureDetector(
                    onTap: () {
                      Navigator.pop(context);
                    },
                    child: const Icon(
                      FlutterIcons.keyboard_backspace_mdi,
                      color: Colors.white,
                    ),
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      RichText(
                        text: TextSpan(
                          children: [
                            TextSpan(
                              text: "Welcome back,\n",
                              style: Theme.of(context)
                                  .textTheme
                                  .headline6
                                  ?.copyWith(color: Colors.white),
                            ),
                            TextSpan(
                              text: "Agent Wesley!",
                              style: Theme.of(context)
                                  .textTheme
                                  .headline6
                                  ?.copyWith(
                                    color: Colors.white,
                                    fontWeight: FontWeight.w600,
                                  ),
                            )
                          ],
                        ),
                      ),
                    ],
                  )
                ],
              ),
            ),
            const SizedBox(height: 50.0),
            Container(
              width: double.infinity,
              constraints: BoxConstraints(
                minHeight: MediaQuery.of(context).size.height - 200.0,
              ),
              decoration: const BoxDecoration(
                borderRadius: BorderRadius.only(
                  topLeft: Radius.circular(30.0),
                  topRight: Radius.circular(30.0),
                ),
                color: Constants.scaffoldBackgroundColor,
              ),
              padding: const EdgeInsets.symmetric(vertical: 24.0),
              child: Column(
                mainAxisSize: MainAxisSize.min,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  const Padding(
                    padding: EdgeInsets.symmetric(horizontal: 24.0),
                    child: Text(
                      "Agent Services",
                      style: TextStyle(
                        color: Color.fromRGBO(19, 22, 33, 1),
                        fontSize: 18.0,
                      ),
                    ),
                  ),
                  const SizedBox(height: 7.0),
                  Container(
                    height: 100.0,
                    child: const Center(
                      // child: ServiceSlider(),
                    ),
                  ),
                ],
              ),
            )
          ],
        ),
      ),
    );
  }
}

原理说明

通过上述修改,每个页面都是独立的Scaffold组件,主页面仅负责根据activeIndex切换渲染目标页面,彻底避免了页面内容嵌套叠加的问题。切换导航项时,旧页面会被完全移除,仅显示当前选中的页面内容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 12:39:51