好的,过了一会儿我找到了答案。
理想的答案应该有一些先决条件
- 它应该在被推到顶部时保持它的状态
- 应该可以从应用中的任何地方推送
- 应该是同一个屏幕 [不是重建的]
- 应该可以有自定义过渡
- 不应以任何方式卸载 [状态丢失]
还有最重要的一个
- 它应该能够到达任何导航器的顶部,但它不应该停留在导航器树中。
解决办法
应用根 Scaffold 中的背景小部件
寻找这个我找到了this背景的中篇文章。
为了我个人的使用,我删除了滑动功能,并添加了一个后退按钮处理程序(因此它充当导航器中的屏幕)。
import 'package:flutter/material.dart';
import 'package:meta/meta.dart';
const _kFlingVelocity = 2.0;
class Backdrop extends StatefulWidget {
final Widget frontLayer;
final Widget backLayer;
final ValueNotifier<bool> panelVisible;
Backdrop(
{@required this.frontLayer, @required this.backLayer, this.panelVisible})
: assert(frontLayer != null),
assert(backLayer != null);
@override
createState() => _BackdropState();
}
class _BackdropState extends State<Backdrop>
with SingleTickerProviderStateMixin {
final _backdropKey = GlobalKey(debugLabel: 'Backdrop');
AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: Duration(milliseconds: 300),
value: (widget.panelVisible?.value ?? true) ? 1.0 : 0.0,
vsync: this,
);
widget.panelVisible?.addListener(_subscribeToValueNotifier);
if (widget.panelVisible != null) {
_controller.addStatusListener((status) {
if (status == AnimationStatus.completed)
widget.panelVisible.value = true;
else if (status == AnimationStatus.dismissed)
widget.panelVisible.value = false;
});
}
}
void _subscribeToValueNotifier() {
if (widget.panelVisible.value != _backdropPanelVisible)
_toggleBackdropPanelVisibility();
}
@override
void didUpdateWidget(Backdrop oldWidget) {
super.didUpdateWidget(oldWidget);
oldWidget.panelVisible?.removeListener(_subscribeToValueNotifier);
widget.panelVisible?.addListener(_subscribeToValueNotifier);
}
@override
void dispose() {
_controller.dispose();
widget.panelVisible?.dispose();
super.dispose();
}
bool get _backdropPanelVisible =>
_controller.status == AnimationStatus.completed ||
_controller.status == AnimationStatus.forward;
void _toggleBackdropPanelVisibility() => _controller.fling(
velocity: _backdropPanelVisible ? -_kFlingVelocity : _kFlingVelocity);
Future<bool> _onWillPop() async {
if (widget.panelVisible.value) {
widget.panelVisible.value = false;
return false;
}
return true;
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) {
final panelDetailsPosition = Tween<Offset>(
begin: Offset(0.0, 1.0),
end: Offset(0.0, 0.0),
).animate(_controller.view);
return WillPopScope(
onWillPop: _onWillPop,
child: Container(
key: _backdropKey,
child: Stack(
children: <Widget>[
widget.backLayer,
SlideTransition(
position: panelDetailsPosition, child: widget.frontLayer),
],
),
));
});
}
}
我在全球商店有final frontPanelVisible = ValueNotifier<bool>(false);,所以我可以从应用程序的任何地方调用它并“推动”这个传送的魔法屏幕。
在我的应用程序的主小部件中,我有这样的东西
class Panels extends StatelessWidget {
final frontPanelVisible = ValueNotifier<bool>(false);
@override
Widget build(BuildContext context) {
return Backdrop(
frontLayer: MainAppScreen(),
backLayer: MagicalScreen(),
panelVisible: frontPanelVisible,
);
}
}
在层次结构中跳转非常神奇,而且,它节省了大量资源 [因为我只有 1 个相同内容的屏幕,而不是 15 个屏幕],也许稍微修改一下,我可以在那里有一个嵌套的导航器.无限可能。