Reputation: 3676
I have been searching for a while and i could not find any option to do this. Is this even possible?
In the following scenario
Page1 > Page2 > Page3 > Page4
From Page4 , can i navigate to Page2 without creating a new Page2?
Desired result:
Page1 >??empty?? > Page3 > Page4 > Page2
Normal result:
Page1 > Page2 > Page3 > Page4 > different Page2
Is this even possible with flutter?
Upvotes: 1
Views: 656
Reputation: 3676
Ok after a while i found an answer.
The ideal answer should have some prerequisites
And the most important one
The solution
A Backdrop widget in the root Scaffold of the app
Looking for this i have found this medium article of a backdrop.
For my personal use i removed the swipe capability, and added a back button handler (so it acts as a screen in a navigator).
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),
],
),
));
});
}
}
I have the final frontPanelVisible = ValueNotifier<bool>(false);
in a global store , so i can call it from anywhere in the app and "push" this magic screen that teleports.
And in the main widget of my app i have something like this
class Panels extends StatelessWidget {
final frontPanelVisible = ValueNotifier<bool>(false);
@override
Widget build(BuildContext context) {
return Backdrop(
frontLayer: MainAppScreen(),
backLayer: MagicalScreen(),
panelVisible: frontPanelVisible,
);
}
}
It's quite magical to jump in the hierarchy, also, it saves a ton of resources [since instead of having 15 screens of the same content i have only 1], and maybe with a little tinkering i can have a nested navigator there . The possibilities are endless.
Upvotes: 1
Reputation: 854
Yes you can back go back from Page4 to Page2
Navigator.popUntil(context, ModalRoute.withName("/screen2"));
Upvotes: 2