#flutter #flutter-web
Вопрос:
Задать вопрос означает, что я пытаюсь создать вложенный навигатор с помощью Navigator 2.0 для своего веб-приложения Flutter. Ниже приведена отправная точка моего приложения.
void main() {
runApp(App());
}
class App extends StatefulWidget {
@override
_AppState createState() => _AppState();
}
class _AppState extends State<App> {
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routeInformationParser: AppRouteParser(), routerDelegate: AppRouterDelegate(),
title: "Demo",
);
}
}
Как вы можете видеть, я добавил MaterialApp.router() для обработки всех навигаций верхнего уровня.
Теперь я хотел добавить вложенный навигатор внутри этого, который будет работать так же, как и выше, и будет правильно обрабатывать изменения URL-адреса. Вот почему я решил использовать тот же виджет MaterialApp.router() внутри в качестве дочернего элемента, что и мой вложенный навигатор.
После этого все работает нормально, но я получаю два отладочных баннера, как показано на рисунке ниже :
Это заставляет меня задуматься, правильно ли я использую метод для достижения результата.
Дочерний навигатор принадлежит виджету страницы 1 корневого навигатора, как показано ниже, это виджет навигатора корневого MaterialApp.маршрутизатор:
class AppRouterDelegate extends RouterDelegate<AppRoute>
with ChangeNotifier, PopNavigatorRouterDelegateMixin<AppRoute> {
final GlobalKey<NavigatorState> _navigatorKey;
bool isPage1A = false;
bool isPage1B = false;
bool isUnknown = false;
AppRouterDelegate() : _navigatorKey = GlobalKey<NavigatorState>();
@override
Widget build(BuildContext context) {
return Navigator(
pages: [
MaterialPage(key: ValueKey("Page 1"),child: Page1(_valueChangeCallback)),
if(isPage1A)
MaterialPage(key: ValueKey("Page 1A"),child: Page1A(_valueChangeCallback)),
if(isPage1B)
MaterialPage(key: ValueKey("Page 1B"),child: Page1B(_valueChangeCallback)),
/* if(isUnknown)
MaterialPage(key: ValueKey("404"),child: TestPage()) */
],
onPopPage: (route,result){print("Pop !!!!"); return route.didPop(result);}
);
}
_valueChangeCallback(bool value,String subPage,[String subPage2]) {
//print("Value change callback");
if(subPage2 == null) {
if(subPage == "A")
isPage1A = value;
else if(subPage == "B")
isPage1B = value;
}
else {
if(subPage2 == "B") {
isPage1A = !value;
isPage1B = value;
}
else if(subPage2 == "A") {
isPage1A = value;
isPage1B = !value;
}
}
notifyListeners();
}
А ниже приведен виджет страницы 1, в котором находится дочерний MaterialApp.router :
class Page1 extends StatefulWidget {
Function valueChangeCallback;
Page1(this.valueChangeCallback);
@override
_Page1State createState() => _Page1State();
}
class _Page1State extends State<Page1> {
@override
Widget build(BuildContext context) {
print("Page 1");
return Scaffold(
body: Column(
children: [
InkWell(
onTap: () {
widget.valueChangeCallback(true,"A");
},
child: Text("Move to Sub Pages")
),
Expanded(child: MaterialApp.router(routeInformationParser: NestedAppRouteInformationParser(), routerDelegate: NestedAppRouterDelegate())),
],
),
);
}
}
Ответ №1:
Если вы посмотрите на приложение.dart MaterialApp-это удобный виджет, который включает в себя несколько «виджетов, которые обычно требуются для приложений material design».
Если бы вы использовали конструктор по умолчанию, для вас был бы настроен объект Навигатора верхнего уровня.
MaterialApp.router () — еще одно удобство. «Создает [Материальное приложение], которое использует [Маршрутизатор] вместо [Навигатора]».
Конструктор маршрутизатора предоставляет вам способ создания приложения MaterialApp, настройки и возврата пользовательского навигатора.
То, что вы делаете, когда используете этот конструктор, — это обертывание виджетов-потомков во все удобные виджеты, которые может предложить MaterialApp(включая баннер отладки).
Для вложенных маршрутизаторов вместо этого вы хотите просто напрямую использовать виджет Router (), и вы избежите вызова всех дополнительных функций, которые MaterialApp предоставляет вам во время инициализации вашего приложения.
Также следует отметить, что в идеале для каждого приложения должен быть только один анализатор информации. в соответствии с примечаниями в маршрутизаторе.дротик, вы должны передать null в Wdiget маршрутизатора nester.
"To opt out of URL updates entirely, pass null for [routeInformationProvider]
/// and [routeInformationParser]. This is not recommended in general, but may be
/// appropriate in the following cases:
///
/// * The application does not target the web platform.
///
/// * **There are multiple router widgets in the application. Only one [Router]
/// widget should update the URL (typically the top-most one created by the
/// [WidgetsApp.router], [MaterialApp.router], or [CupertinoApp.router]).**
///
/// * The application does not need to implement in-app navigation using the
/// browser's back and forward buttons."
class _Page1State extends State<Page1> {
@override
Widget build(BuildContext context) {
print("Page 1");
return Scaffold(
body: Column(
children: [
InkWell(
onTap: () {
widget.valueChangeCallback(true,"A");
},
child: Text("Move to Sub Pages")
),
Expanded(child: Router(routeInformationParser: null, routerDelegate: NestedAppRouterDelegate(), backButtonDispatcher: ChildBackButtonDispatcher(Router.of(context).backButtonDispatcher),)),
],
),
);
}
Также предоставление диспетчера дочерней кнопки «Назад», как показано на рисунке, позволит вам связаться с родительским маршрутизатором при выполнении нажатия кнопки «Назад»…Надеюсь, это поможет!