Здесь есть аналогичный вопрос без ответа: Экран FullscreenDialog не закрывает нижнюю панель навигации , но я хочу предоставить больше контекста, чтобы посмотреть, поможет ли это найти решение. Мы начнем с моего main.dart
сверху, я создаю MaterialApp
, который создает собственный DynamicApp
. Вот важные вещи:
Widget build(BuildContext context) {
var _rootScreenSwitcher = RootScreenSwitcher(key: switcherKey);
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.green,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
builder: (context, child) {
return DynamicApp(
navigator: locator<NavigationService>().navigatorKey,
child: child,
switcher: _rootScreenSwitcher,
);
},
navigatorKey: locator<NavigationService>().navigatorKey,
onGenerateRoute: (routeSettings) {
switch (routeSettings.name) {
case SettingsNavigator.routeName:
return MaterialPageRoute(
builder: (context) => SettingsNavigator(),
fullscreenDialog: true);
default:
return MaterialPageRoute(builder: (context) => SettingsNavigator());
}
},
home: _rootScreenSwitcher,
);
}
My DynamicApp
настраивает root Scaffold
следующим образом:
Widget build(BuildContext context) {
return Scaffold(
drawer: NavigationDrawer(
selectedIndex: _selectedIndex,
drawerItems: widget.drawerItems,
headerView: Container(
child: Text('Drawer Header'),
decoration: BoxDecoration(color: Colors.blue),
),
onNavigationItemSelect: (index) {
onTapped(index);
return true; // true means that drawer must close and false is Vice versa
},
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
onTap: (index) {
onTapped(index);
},
currentIndex: _selectedIndex,
items: bottomNavBarItems,
showUnselectedLabels: false,
),
body: widget.child,
);
}
Дочерний элемент DynamicApp
- это виджет, называемый RootScreenSwitcher
, который является IndexedStack
и управляет переключением экранов из моего BottomNavigationBar
, а также при выборе элементов в Drawer
. Вот RootScreenSwitcher
:
class RootScreenSwitcherState extends State<RootScreenSwitcher> {
int _currentIndex = 0;
int get currentIndex => _currentIndex;
set currentIndex(index) {
setState(() {
_currentIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
top: false,
child: IndexedStack(
index: _currentIndex,
children: menuItems.map<Widget>((MenuItem item) {
return item.widget;
}).toList(),
),
),
);
}
void switchScreen(int index) {
setState(() {
_currentIndex = index;
});
}
}
Каждый из основных разделов приложения имеет свой собственный экран Navigator
и root. Все это работает нормально, и я доволен общей структурой навигации. Каждый экран root имеет свой собственный AppBar
, но глобальные Drawer
и BottomNavigationBar
обрабатываются в DynamicApp
, поэтому мне не нужно постоянно устанавливать их на других экранах Scaffold
.
Итак, пришло время представить другие разделы приложения, которые не обслуживаются нижней панелью вкладок и могут быть представлены с помощью Drawer
или других кнопок действий. Каждый из этих новых разделов должен быть модальным fullscreenDialog
экранами, чтобы они скользили вверх снизу, но имели свою собственную навигацию и каркас.
Моя проблема в том, что когда я перехожу на свой экран SettingsNavigator
, он скользит вверх из-за BottomNavigationBar
, а не поверх всего. Вот метод onGenerateRoute
из MaterialApp
:
onGenerateRoute: (routeSettings) {
switch (routeSettings.name) {
case SettingsNavigator.routeName:
return MaterialPageRoute(
builder: (context) => SettingsNavigator(),
fullscreenDialog: true);
default:
return MaterialPageRoute(builder: (context) => SettingsNavigator());
}
}
Я новичок во Flutter и не совсем понимаю, как маршрутизация работает с контекстами, поэтому мне интересно, контекст экрана, который вызывает метод navigateTo
из Navigator
становится основным контекстом сборки и, следовательно, не находится на вершине дерева виджетов?
gif здесь: https://www.dropbox.com/s/nwgzo0q28cqk61p/FlutteRModalProb.gif?dl=0
Вот древовидная структура, показывающая, что скаффолд для экрана настроек был помещен внутри DynamicApp
Scaffold
. Модальное окно должно располагаться выше DynamicApp
. введите описание изображения здесь
Может ли кто-нибудь пролить свет на это?
ОБНОВЛЕНИЕ: я попытался создать и поделиться уникальным ключом ScaffoldState
для экранов панели вкладок, а затем на странице настроек есть другой ключ. Это не имело значения. Теперь мне интересно, имеет ли это BuildContext
тот же родительский элемент.
ОБНОВЛЕНИЕ ОБНОВЛЕНИЕ: вчера вечером у меня был прорыв, который заставил меня понять, что просто невозможно использовать встроенные скаффолды в в том виде, в каком они есть у меня сейчас. Проблема в том, что у меня есть каркас root с именем DynamicApp
, который сохраняет мои Drawer
и BottomNavigationBar
, но загрузка других страниц Scaffold
в тело означает, что модальные окна вставляются в это тело и за BottomNavigationBar
. Чтобы решить проблему, вы должны создать подкласс BottomNavigationBar
и ссылаться на него в каждом Scaffold
; что означает инкапсуляцию всех бизнес-логов c, поэтому он использует ChangeNotifier
для изменения состояния при взаимодействии с навигацией. По сути, Flutter требует разделения задач на вашу архитектуру, что, я думаю, хорошо. Я напишу лучший ответ, когда сделаю всю дополнительную работу.