应用程序有一个
BottomNavigationBarItem
,像往常一样,它可以在屏幕之间切换。
我希望更改一个屏幕的功能,以便当方向切换为横向时,另一个屏幕被推送到堆栈上。目的是这个新屏幕将覆盖所有内容并且没有导航栏。
我尝试了以下方法:
@override
Widget build(BuildContext context) {
return OrientationBuilder(
builder: (BuildContext context, Orientation orientation) {
if (orientation == Orientation.portrait) {
return Column(
// regular content
}
} else {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => MyLandscapeViewWidget(module: widget.module)));
}
}
这不起作用,因为
else
子句 - 在横向模式下触发 - 需要返回一个小部件。
最好的解决方案是什么?
谢谢
使用
Navigator.push
的问题是它构建了一个新的小部件屏幕并丢弃了前一个小部件屏幕。您正在寻找的是一个 OverlayEntry
小部件。 OverlayEntry 在自己的小部件树中独立构建并管理自己的构建生命周期。
这里是一个演示如何使用 OverlayEntry 的示例。
class MyOverlayScreen {
static OverlayEntry? _overlayEntry;
static void closeOverlayIfVisible() {
if (_overlayEntry == null) {
return;
}
_overlayEntry?.remove();
_overlayEntry = null;
}
static void show(BuildContext context) {
if (_overlayEntry != null) return;
_overlayEntry = OverlayEntry(
builder: (context) {
return Material(
child: Container(
width: double.infinity,
height: MediaQuery.of(context).size.height,
color: Colors.red,
child: const Center(
child: Text("Overlay Screen"),
)));
},
);
Overlay.of(context).insert(_overlayEntry!);
}
}
您现在可以修改代码以显示/隐藏覆盖小部件。
OrientationBuilder(
builder: (BuildContext context, Orientation orientation) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (orientation == Orientation.landscape) {
MyOverlayScreen.show(context);
} else {
MyOverlayScreen.closeOverlayIfVisible();
}
});
...
我添加了
PostFrameCallback
以确保首先构建以消除 setState() 或 markNeedsBuild() 错误。
作为奖励,这里是 OverlayEntry 的另一个使用示例。即使在屏幕之间导航时,它也用于维护活动对话框屏幕https://dartpad.dev/?id=cbf43c2a652accbff41732d4489c7eb6