如何处理Flutter底部导航栏按下返回键时回到首页的问题
Flutter底部导航栏返回键逻辑修复方案
问题原因
- 当前底部导航切换仅修改同页面下的渲染组件,没有新增路由栈记录,系统返回键触发时会直接弹出根路由,导致应用直接关闭。
修复步骤
使用Flutter官方提供的返回拦截组件PopScope(Flutter 3.16及以上版本适用,低于该版本可替换为已废弃的WillPopScope),自定义返回事件逻辑:
- 当前选中非首页导航项时,点击返回键自动切回首页
- 当前已在首页时,点击返回键走系统默认退出逻辑
完整修改后代码
import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); static const String _title = 'Flutter Code Sample'; @override Widget build(BuildContext context) { return const MaterialApp( title: _title, home: MyStatefulWidget(), ); } } class MyStatefulWidget extends StatefulWidget { const MyStatefulWidget({Key? key}) : super(key: key); @override State<MyStatefulWidget> createState() => _MyStatefulWidgetState(); } class _MyStatefulWidgetState extends State<MyStatefulWidget> { int _selectedIndex = 0; static const TextStyle optionStyle = TextStyle(fontSize: 30, fontWeight: FontWeight.bold); static const List<Widget> _widgetOptions = <Widget>[ Text( 'Index 0: Home', style: optionStyle, ), Text( 'Index 1: Business', style: optionStyle, ), Text( 'Index 2: School', style: optionStyle, ), ]; void _onItemTapped(int index) { setState(() { _selectedIndex = index; }); } @override Widget build(BuildContext context) { // 新增PopScope拦截返回事件 return PopScope( canPop: _selectedIndex == 0, // 只有在首页时允许默认返回(退出应用) onPopInvoked: (didPop) { if (didPop) return; // 非首页时点击返回,切回首页 setState(() { _selectedIndex = 0; }); }, child: Scaffold( appBar: AppBar( title: const Text('BottomNavigationBar Sample'), ), body: Center( child: _widgetOptions.elementAt(_selectedIndex), ), bottomNavigationBar: BottomNavigationBar( items: const <BottomNavigationBarItem>[ BottomNavigationBarItem( icon: Icon(Icons.home), label: 'Home', ), BottomNavigationBarItem( icon: Icon(Icons.business), label: 'Business', ), BottomNavigationBarItem( icon: Icon(Icons.school), label: 'School', ), ], currentIndex: _selectedIndex, selectedItemColor: Colors.amber[800], onTap: _onItemTapped, ), ), ); } }
低版本Flutter兼容方案
如果你使用的Flutter版本低于3.16,可将PopScope替换为WillPopScope,代码如下:
@override Widget build(BuildContext context) { return WillPopScope( onWillPop: () async { if (_selectedIndex != 0) { setState(() { _selectedIndex = 0; }); return false; // 拦截返回事件 } return true; // 不拦截,走默认退出逻辑 }, child: Scaffold( // 原有Scaffold代码保持不变即可 ), ); }
内容的提问来源于stack exchange,提问作者Aung Zin Moe
相关产品推荐
相关产品推荐

