我正在开发一个带有 NavigationPage 的 Flutter 应用程序,该应用程序使用 IndexedStack 通过 BottomNavigationBar 管理不同的屏幕。每个屏幕都包含在具有自己的 GlobalKey 的 Navigator 中。我的问题是处理管理屏幕上的后退按钮按下。
以下是我目前在导航页面中管理后退按钮按下的方法:
class NavigationPage extends StatefulWidget {
@override
_NavigationPageState createState() => _NavigationPageState();
}
class _NavigationPageState extends State<NavigationPage> {
int _selectedIndex = 0;
bool isKeyboardVisible = false; // Update this based on keyboard visibility
List<GlobalKey<NavigatorState>> _navigatorKeys = [
GlobalKey<NavigatorState>(),
GlobalKey<NavigatorState>(),
// Add more keys if you have more tabs
];
Future<bool> systemBackButtonPressed() async {
if (_selectedIndex == 0) {
return Future.value(true); // Exit the app or handle it as needed
} else {
var currentState = _navigatorKeys[_selectedIndex].currentState;
if (currentState != null && currentState.canPop()) {
currentState.pop();
return Future.value(false);
} else {
setState(() {
_selectedIndex = 0;
});
return Future.value(false);
}
}
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: systemBackButtonPressed,
child: Scaffold(
body: IndexedStack(
index: _selectedIndex,
children: _navigatorKeys.map((key) {
return Navigator(
key: key,
onGenerateRoute: (routeSettings) {
return MaterialPageRoute(
builder: (context) => getPage(_selectedIndex),
);
},
);
}).toList(),
),
bottomNavigationBar: Visibility(
visible: !isKeyboardVisible,
child: BottomNavBar(
selectedIndex: _selectedIndex,
onItemTapped: (index) {
setState(() {
_selectedIndex = index;
});
},
),
),
),
);
}
Widget getPage(int index) {
switch (index) {
case 0:
return HomeScreen();
case 1:
return ManagementScreen();
// Add more cases if you have more tabs
default:
return HomeScreen();
}
}
}
这是我的管理屏幕的代码:
class ManagementScreen extends StatelessWidget {
Future<bool> _onWillPop(BuildContext context) async {
debugPrint("ManagementScreen onWillPop triggered");
// Add any specific logic you want here
return true; // or false to prevent the screen from popping
}
@override
Widget build(BuildContext context) {
final height = MediaQuery.sizeOf(context).height;
final width = MediaQuery.sizeOf(context).width;
return WillPopScope(
onWillPop: () => _onWillPop(context), //this not working
child: Scaffold(
body: SafeArea(
child: Container(
height: height * 1,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/app_background1.png'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
children: [
// Your content here
],
),
),
),
),
),
);
}
}
问题:
当
systemBackButtonPressed
为 0 时,NavigationPage 中的 _selectedIndex
方法可以正常工作,但是当导航到 ManagementScreen 时, onWillPop
回调不会被触发。我希望当我按下 ManagementScreen 上的后退按钮时会调用 onWillPop
方法,但它似乎没有按预期工作。
问题在于您如何构建
WillPopScope
小部件。在您当前的设置中,ManagementScreen 中的 WillPopScope
会被绕过,因为 WillPopScope
中的 NavigationPage
会首先拦截后退按钮按下的操作。
解决方法如下:
选项 1:将后退按钮处理委托给 ManagementScreen:
从 NavigationPage 中删除 WillPopScope。 在 NavigationPage 中,在
systemBackButtonPressed
方法内部,不要直接弹出当前导航器,而是调用特定 ManagementScreen 的 _onWillPop
方法,如下所示:
Future<bool> systemBackButtonPressed() async {
if (_selectedIndex == 0) {
return Future.value(true);
} else {
// Get the current ManagementScreen navigator
var currentState = _navigatorKeys[_selectedIndex].currentState;
if (currentState != null) {
// Delegate back button handling to ManagementScreen
return currentState.maybePop(); // Use maybePop to avoid errors if not at root
} else {
setState(() {
_selectedIndex = 0;
});
return Future.value(false);
}
}
}
此方法允许 ManagementScreen 使用其
_onWillPop
方法处理自己的后退按钮逻辑。
选项 2:在 NavigationPage 中使用单个 WillPopScope:
将 WillPopScope 保留在 NavigationPage 中。 修改 NavigationPage 中的
onWillPop
回调,在弹出导航器之前首先检查当前屏幕的 _onWillPop
方法(使用 _navigatorKeys[_selectedIndex].currentState
访问)。
Future<bool> systemBackButtonPressed() async {
if (_selectedIndex == 0) {
return Future.value(true); // Exit the app or handle it as needed
} else {
var currentState = _navigatorKeys[_selectedIndex].currentState;
if (currentState != null) {
// Check ManagementScreen's onWillPop first
bool canPop = await currentState.maybePop();
if (canPop) {
return canPop;
} else {
// ManagementScreen onWillPop returned false, handle fallback
setState(() {
_selectedIndex = 0;
});
return Future.value(false);
}
} else {
setState(() {
_selectedIndex = 0;
});
return Future.value(false);
}
}
}