Моя цель состоит в том, чтобы A был интерфейсом и разделял код реализации из заголовков.
blockquote>В этом случае сделайте функцию-член чистой виртуальной в классе A.
class A { // ... virtual void doWork() = 0; };
На самом деле вам придется использовать вложенные Navigator
, когда у вас есть суб-навигационный поток или внутреннее путешествие. Пожалуйста, ознакомьтесь с документами о наложении навигаторов .
Однако, чтобы получить доступ к корневому навигатору, вы можете рекурсивно искать родителя Navigator
из текущего Navigator
и возвращать текущий Navigator
, когда у него нет родителя Navigator
.
Пример:
NavigatorState getRootNavigator(BuildContext context) {
final NavigatorState state = Navigator.of(context);
try {
return getRootNavigator(state.context);
} catch (e) {
return state;
}
}
//use it from any widget like
getRootNavigator(context);
РЕДАКТИРОВАТЬ:
Решение 1:
К получить конкретного родителя Navigator
, я могу подумать о расширении текущего класса Navigator
, чтобы принять id
и найти Navigator
по id
. Примерно так:
class NavigatorWithId extends Navigator {
const NavigatorWithId(
{Key key,
@required this.id,
String initialRoute,
@required RouteFactory onGenerateRoute,
RouteFactory onUnknownRoute,
List<NavigatorObserver> observers = const <NavigatorObserver>[]})
: assert(onGenerateRoute != null),
assert(id != null),
super(
key: key,
initialRoute: initialRoute,
onGenerateRoute: onGenerateRoute,
onUnknownRoute: onUnknownRoute,
observers: observers,
);
// when id is null, the `of` function returns top most navigator
final int id;
static NavigatorState of(BuildContext context, {int id, ValueKey<String> key}) {
final NavigatorState state = Navigator.of(
context,
rootNavigator: id == null,
);
if (state.widget is NavigatorWithId) {
// ignore: avoid_as
if ((state.widget as NavigatorWithId).id == id) {
return state;
} else {
return of(state.context, id: id);
}
}
return state;
}
}
Используйте NavigatorWithId
вместо Navigator
всякий раз, когда требуется, например,
return NavigatorWithId(
id: 1,
initialRoute: '/',
onGenerateRoute: (_) =>
MaterialPageRoute<dynamic>(builder: (_) => const YourPage()),
)
, а затем обращайтесь к нему, как:
NavigatorWithId.of(context, id: 1)
[1142 ] Решение 2:
Передайте ValueKey
навигатору и создайте вспомогательную функцию, которая бы соответствовала клавише и вернула требуемый Navigator
.
Функция что-то вроде
NavigatorState getNavigator(BuildContext context, {bool rootNavigator = false, ValueKey<String> key}) {
assert(rootNavigator != null);
final NavigatorState state = Navigator.of(
context,
rootNavigator: rootNavigator,
);
if (rootNavigator) {
return state;
} else if (state.widget.key == key) {
return state;
}
try {
return getNavigator(state.context, key: key);
} catch (e) {
return state;
}
}
Используйте
return Navigator(
key: const ValueKey<String>('Navigator1'),
initialRoute: '/',
onGenerateRoute: (_) =>
MaterialPageRoute<void>(builder: (_) => const RootPage()),
);
и получите доступ к ней, как
getNavigator(context, key: const ValueKey<String>('Navigator1'))
Недостаток этого метода я вижу не все типы ключей будут поддерживаться.
Примечание. Я не претендую на то, чтобы какое-либо из приведенных выше решений было наилучшим или оптимальным. Это несколько методов, которые я придумал. Если кто-то может предложить лучший подход, я стремлюсь учиться:)
Надеюсь, это поможет!
В большинстве случаев у вас будет только 2 штурмана.
Что означает получить вложенный, выполните:
Navigator.of(context)
И чтобы получить корневой выполните:
Navigator.of(context, rootNavigator: true)
Для более сложной архитектуры, проще всего использовать GlobalKey (так как вы никогда не будете читать Navigators во время build )
final GlobalKey<NavigatorState> key =GlobalKey();
final GlobalKey<NavigatorState> key2 =GlobalKey();
class Foo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: key,
home: Navigator(
key: key2,
),
);
}
}
, который затем можно использовать следующим образом:
key.currentState.pushNamed('foo')