В моем приложении я хочу иметь пользовательскую навигацию (изменить только часть экрана и сохранить историю того, что я делаю внутри него). Для этой цели я использую навигатор, и он отлично работает для простой навигации. Однако я хочу обработать кнопку «Назад» Android. Очевидно, во Flutter есть проблема, которая заставляет меня обрабатывать кнопку «Назад» в родительском виджете Navigator: https://github.com/флуттер/флуттер/issues/14083
Из-за этого мне нужно получить экземпляр моего навигатора в дочерних элементах и вызвать для него pop(). Я пытаюсь использовать GlobalKey для этого.
Я пытаюсь заставить его работать какое-то время и сделал пример проекта, чтобы проверить это. Вот мой код:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(title: 'Navigation Basics', home: MainWidget()));
}
class MainWidget extends StatelessWidget {
final GlobalKey<NavigatorState> navigatorKey = GlobalKey();
@override
Widget build(BuildContext context) {
return SafeArea(
child: WillPopScope(
onWillPop: () => navigatorKey.currentState.maybePop(),
child: Scaffold(
body: Padding(
child: Column(
children: <Widget>[
Text("Toto"),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Expanded(
child: RaisedButton(
child: Text('First'),
onPressed: () {
navigatorKey.currentState.pushNamed('/first');
// Navigator.push(
// context,
// MaterialPageRoute(builder: (context) => SecondRoute()),
// );
},
)),
Expanded(
child: RaisedButton(
child: Text('Second'),
onPressed: () {
navigatorKey.currentState.pushNamed('/second');
},
))
],
),
Expanded(
child: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(color: Colors.red),
),
ConstrainedBox(
constraints: BoxConstraints.expand(),
child: _getNavigator()),
],
)),
],
),
padding: EdgeInsets.only(bottom: 50),
))));
}
Navigator _getNavigator() {
return Navigator(
key: navigatorKey,
initialRoute: '/',
onGenerateRoute: (RouteSettings settings) {
WidgetBuilder builder;
switch (settings.name) {
case '/':
builder = (BuildContext _) => FirstRoute();
break;
case '/second':
builder = (BuildContext _) => SecondRoute();
break;
default:
throw new Exception('Invalid route: ${settings.name}');
}
return new MaterialPageRoute(builder: builder, settings: settings);
});
}
}
class FirstRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
RaisedButton(
child: Text("GO TO FRAGMENT TWO"),
onPressed: () => Navigator.of(context).pushNamed("/second"),
)
],
),
decoration: BoxDecoration(color: Colors.green),
);
}
}
class SecondRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
RaisedButton(
child: Text("GO TO FRAGMENT ONE"),
onPressed: () => Navigator.of(context).pop(),
)
],
),
decoration: BoxDecoration(color: Colors.blue),
);
}
}
Однако это не работает так, как хотелось бы. Похоже, что навигатор по умолчанию все еще используется: после открытия SecondRoute и нажатия кнопки возврата Android он просто покидает приложение, а не возвращается к первому маршруту.
Как я могу достичь того, чего хочу?





Следуя документации onWillPop:
/// Called to veto attempts by the user to dismiss the enclosing [ModalRoute].
///
/// If the callback returns a Future that resolves to false, the enclosing
/// route will not be popped.
final WillPopCallback onWillPop;
ваш обработчик должен указать, что окружающий маршрут не должен быть закрыт, поэтому возврат false решит вашу проблему.
изменение вашего обработчика на это работает:
onWillPop: () async {
navigatorKey.currentState.maybePop();
return false;
},
Вместо navigatorKey.currentState.maybePop(); return false; вы можете использовать return !await navigatorKey.currentState.maybePop();, чтобы позволить всплывать внешнему навигатору, когда внутренний уже находится вверху.
Как заставить работать функцию «прокрутить назад» в iOS при использовании виджета WillPopScope?