如何解决Flutter:我有一个持久的自定义叠加层,里面有一个导航器如何根据导航页面显示/隐藏叠加层?
我想实现一个使用 auto_route 包在其中的页面之间导航的叠加层。我希望叠加层能够跨页面持续存在,因此如果搜索栏或抽屉处于打开状态,则一旦您推送或弹出页面,其外观仍然存在。
问题来自下一个要求:我希望根据要导航到的页面隐藏或显示它。也就是说,如果我在显示叠加层的“Page1”中并且我执行“Navigator.pushNamed(/Page2)”并且 Page2 隐藏了叠加层,则叠加层会隐藏。如果我执行“Navigator.pop()”,它会返回到“Page1”,再次显示叠加层。
由于页面是由“ExtendedNavigator”类提供的,并且首先构建了 Overlay 本身,因此在构建时我无法知道 Navigator 导航到的位置或当前正在构建的页面。我需要事先知道这些信息才能相应地隐藏或显示叠加层。
我尝试了几种解决方案,但都无济于事。
第一种方法
在需要渲染的每个页面中实例化 Overlay,并使用继承的 Widget 来维护状态。
问题:无法同步所有叠加层的状态。键不能被重用,它们的状态也不能被复制(例如,对于 ScaffoldState)。因此,每当其中一个叠加层发生变化时,我都应该将相同的更改复制到所有其他叠加层以相应地更改它们的状态。此外,无法实例化具有特定状态的 Scaffold。
此解决方案的代码大致如下:
class Page1 extends StatefulWidget {
Page1 ({
Key key,}) : super(key: key);
@override
_Page1State createState() => _Page1State();
}
class _Page1State extends State<Page1> {
@override
Widget build(BuildContext context) {
return Overlay(
child: (...)
);
}
}
class Page2 extends StatefulWidget {
Page2 ({
Key key,}) : super(key: key);
@override
_Page2State createState() => _Page2State();
}
class _Page2State extends State<Page2> {
@override
Widget build(BuildContext context) {
return Overlay(
child: (...)
);
}
}
class OverlayData extends InheritedWidget {
bool _hidden = true;
OverlayData({
Key key,@required Widget child,}) : super(key: key,child: child);
static OverlayData of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<OverlayData>();
}
void setHiddenTo(bool value) {
_hidden = value;
print("Overlay is now in state: " + value.toString());
}
bool isHidden() {
return _hidden;
}
@override
bool updateShouldNotify(OverlayData oldWidget) =>
_hidden != oldWidget._hidden;
}
//// Main
void main() {
runApp(App());
}
class App extends StatefulWidget {
@override
State<StatefulWidget> createState() => _AppState();
}
class _AppState extends State<App> {
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
builder: ExtendedNavigator.builder<router.Router>(
router: router.Router(),builder: (context,extendedNav) => Theme(
data: ThemeData(
brightness: Brightness.light,),child: OverlayData(child: Overlay(child: extendedNav)),color: StyleValues.blue,);
}
}
第二种方法
每次手动推送/弹出到另一个页面时,使用其 GlobalKey 手动触发叠加层的隐藏/显示。推送页面时,我可以使用 [Guards] 来检查我要导航到的页面是显示还是隐藏了覆盖的页面,并使用覆盖的键触发更改。
问题:当我使用 Android 按钮弹出时,我不知道我弹出的是哪个页面并相应地触发更改。即使我用“WillPopScope”包裹了我的叠加层,我仍然不知道我弹出的是哪个页面,所以它没有用。
此代码大致如下所示:
/// Main
void main() {
runApp(App());
}
class App extends StatefulWidget {
@override
State<StatefulWidget> createState() => _AppState();
}
class _AppState extends State<App> {
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
builder: ExtendedNavigator.builder<router.Router>(
router: router.Router(),guards: [HideGuard(),ShowGuard()]
builder: (context,child: Overlay(child: extendedNav),);
}
}
/// Overlay
class Overlay extends StatefulWidget {
final Widget body;
Overlay({this.body});
@override
OverlayState createState() => OverlayState(this.body);
}
class OverlayState extends State<Overlay> {
final Widget body;
bool _hidden;
OverlayState(this.body);
void setHiddenTo(bool value){
if (value != _hidden)
{
SetState(() {
_hidden = value;
})
}
}
@override
Widget build(BuildContext context) {
/// Here I check if it is hidden or not
if (_hidden) {
return body;
}
return Scaffold(
appBar: PreferredSize(
child: AppBar(...)
),/// Bottom Bar
bottomNavigationBar: (...),/// Content (Second Scaffold to render Drawer behind AppBar and BottomBar)
body: Scaffold(
key: _scaffoldKey,drawer: Drawer(
child: (...)
),body: body,);
}
}
/// The router
@MaterialAutoRouter(routes: <AutoRoute>[
MaterialRoute(path: PageRoutes.page1,page: Page1,initial: true,guards: [HideGuard]),MaterialRoute(path: PageRoutes.page2,page: Page2,guards: [ShowGuard]),MaterialRoute(path: PageRoutes.page3,page: Page3,])
class $Router {}
/// The Key (in a separate class)
class Keys{
GlobalKey<OverlayState> overlayKey = GlobalKey<OverlayState>();
}
/// A guard
class ShowGuard extends RouteGuard {
@override
Future<bool> canNavigate(
ExtendedNavigatorState navigator,String routeName,Object arguments) async {
Keys.OverlayKey.currentState.setHiddenTo(false);
}
}
class HideGuard extends RouteGuard {
@override
Future<bool> canNavigate(
ExtendedNavigatorState navigator,Object arguments) async {
Keys.OverlayKey.currentState.setHiddenTo(true);
}
}
我应该如何解决这个问题?有没有办法在构建覆盖层之前检索将要推送/弹出的当前页面?有没有办法让多个小部件共享相同的状态? 预先感谢您的帮助。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。