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

使用persistent_bottom_nav_bar登出时触发Navigator断言异常求助

问题:使用persistent_bottom_nav_bar登出时触发断言异常

我使用persistent_bottom_nav_bar: ^5.0.2包构建多页面Flutter应用,每个页面的AppBar都设有登出按钮,点击登出时触发以下断言异常。

实现代码

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

  @override
  State<LoginPage> createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  GlobalKey<FormState> formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: ListView(
          children: [
            Form(
              key: formKey,
              child: Column(
                children: [
                  FloatingActionButton(
                    onPressed: () async {
                      if (formKey.currentState!.validate()) {
                        if (accessToken != null) {
                          Navigator.push(
                            context,
                            MaterialPageRoute(
                              builder: (context) => MultiProvider(
                                providers: [
                                  ChangeNotifierProvider<DashboardProvider>(
                                      create: (context) => DashboardProvider()),
                                ],
                                child: Dashboard(),
                              ),
                            ),
                          );
                        }
                      }
                    },
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

////////////////////////////////////////////////////////////////////////////////
class Dashboard extends StatefulWidget {
  Dashboard({Key? key}) : super(key: key);

  static PersistentTabController controller =
      PersistentTabController(initialIndex: 0);
  @override
  State<Dashboard> createState() => _DashboardState();
}

class _DashboardState extends State<Dashboard> {
  List<Widget> _buildScreen() {
    return [
      HomePage(),
      FoTotalOrdersLocation(),
    ];
  }

  List<PersistentBottomNavBarItem> _navigationBarItems() {
    return [
      PersistentBottomNavBarItem(
        icon: Icon(
          Icons.home,
          size: 30,
        ),
        textStyle: TextStyle(fontSize: 20),
        title: ("Home"),
      ),
      PersistentBottomNavBarItem(
        icon: Icon(
          Icons.location_on,
          size: 30,
        ),
        textStyle: TextStyle(fontSize: 20),
        title: ("Location"),
      ),
    ];
  }

  @override
  void initState() {
    super.initState();
    if (Dashboard.controller.index == 0) {}
  }

  @override
  Widget build(BuildContext context) {
    print("build called");
    return Scaffold(
      body: ChangeNotifierProvider(
        create: (context) => FoHomePageProvider(context),
        child: PersistentTabView(
          context,
          controller: Dashboard.controller,
          screens: _buildScreen(),
          items: _navigationBarItems(),
          onItemSelected: (val) async {},
        ),
      ),
    );
  }
}

///////////////////////////////////////////////////////////////////////////////////////////

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          onPressed: () {
            Navigator.popUntil(
              context,
              ModalRoute.withName(' /loginPage'),
            );
          },
          icon: Icon(Icons.logout),
        ),
      ),
      body: ElevatedButtonWidget(
        text: "Next",
        onPressed: () {
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => UsersPage(),
            ),
          );
        },
      ),
    );
  }
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          onPressed: () {
            Navigator.popUntil(
              context,
              ModalRoute.withName(' /loginPage'),
            );
          },
          icon: Icon(Icons.logout),
        ),
      ),
      body: Text("Users page"),
    );
  }
} 

异常信息

════════ Exception caught by widgets library ═══════════════════════════════════
以下断言在构建Navigator(dirty, dependencies: [UnmanagedRestorationScope, HeroControllerScope], state: NavigatorState#5900b(tickers: tracking 0 tickers))时抛出:
'package:flutter/src/widgets/navigator.dart': 断言失败:第5140行第12位:'_history.isNotEmpty':不为真。
package:flutter/…/widgets/navigator.dart:5140
2

原因分析与修复方案

核心原因

  1. 路由名称匹配错误:你在Navigator.popUntil中使用了带前置空格的' /loginPage',但登录页从未注册过这个路由名称,导致无法匹配到目标路由,最终触发栈为空的断言异常。
  2. 嵌套Navigator冲突:PersistentTabView内部会创建独立的Navigator实例,子页面中调用的Navigator.popUntil操作的是这个内部Navigator,而非根Navigator。内部路由栈中不存在登录页,清空栈后就会触发_history.isNotEmpty断言失败。

修复步骤

1. 改用根Navigator执行登出操作

在所有登出按钮的点击逻辑中,指定使用根Navigator,并通过pushReplacement直接替换为登录页(避免栈操作异常):

// HomePage和UsersPage中的登出按钮逻辑替换为:
onPressed: () {
  Navigator.of(context, rootNavigator: true).pushReplacement(
    MaterialPageRoute(builder: (context) => LoginPage()),
  );
},

2. 移除静态PersistentTabController

Dashboard中静态的PersistentTabController可能引发页面状态异常,改为在State中初始化:

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

  @override
  State<Dashboard> createState() => _DashboardState();
}

class _DashboardState extends State<Dashboard> {
  late PersistentTabController _controller;

  @override
  void initState() {
    super.initState();
    _controller = PersistentTabController(initialIndex: 0);
  }

  // 后续代码中用_controller替代Dashboard.controller
}

3. 可选:使用命名路由优化跳转

如果项目规模较大,建议在MaterialApp中注册命名路由,进一步简化跳转逻辑:

MaterialApp(
  initialRoute: '/login',
  routes: {
    '/login': (context) => LoginPage(),
    '/dashboard': (context) => Dashboard(),
  },
);

// 登出逻辑可改为:
Navigator.of(context, rootNavigator: true).pushReplacementNamed('/login');

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 23:25:18