Back to view in flutter - flutter

i have a little problem with the Navigator in flutter. I have 3 windows: (Login -> Home -> Orders). But when I go from Login to Home, everything works fine, but if I go from Home to Orders and use the android back button, it returns me to the Login window, that is, until the first view, not the second.
My code Navigation of Login:
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => HomeScreen(),
),
);
My Code Navigation of HomeScreen
Navigator.push(this.context,
MaterialPageRoute(
builder: (context) =\> Orders(
numTable: numTable,
),
)
);

Solution : use pushAndRemoveUntil or pushReplacement at the LoginPage
class LoginPage extends StatelessWidget {
const LoginPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: InkWell(
onTap: ()=>Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) => HomePage(),
)
,(Route<dynamic> route) => false), child: Center(child: Text("LoginPage"),)),
);
}
}
------------
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: InkWell(
onTap: ()=>Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => OrdersPage(),
))
, child: Center(child: Text("HomePage"),)),
);
}
}
---------------
class OrdersPage extends StatelessWidget {
const OrdersPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: Text("OrdersPage"),),
);
}
}

if users login successfully use in Login pushReplacement
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => HomeScreen(),
),
);
in HomeScreen
Navigator.push(this.context,
MaterialPageRoute(
builder: (context) =\> Orders(
numTable: numTable,
),
)
);
when click android back button will go window HomeScreen

You can follow this approach which does what you want, just do Navigator.of(context).push(route) on each page:
class Login extends StatefulWidget {
const Login({Key? key}) : super(key: key);
#override
State<Login> createState() => _LoginState();
}
class _LoginState extends State<Login> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Login'),
),
body: Center(
child: Column(
children: [
TextButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const Home(),
),
);
},
child: const Text('HOME'),
),
],
),
),
);
}
}
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home'),
),
body: Column(
children: [
TextButton(onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const Orders(),
),
);
}, child: const Text('Orders'))
],
),
);
}
}
class Orders extends StatefulWidget {
const Orders({Key? key}) : super(key: key);
#override
State<Orders> createState() => _OrdersState();
}
class _OrdersState extends State<Orders> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Orders'),
),
body: Column(
children: [
TextButton(onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const Home(),
),
);
}, child: const Text('Home'))
],
),
);
}
}

Although there are answers to your question using the Navigator from the Material package, I would like to provide you with a tip for much simpler navigation in Flutter: Use the Get package.
With Get, this code:
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => HomeScreen(),
),
);
can be replaced with this code:
Get.to(() => HomeScreen());
In your example, you will then use the following code to go from Login to Home when a user has been authenticated:
Get.offAll(() => HomeScreen());
After that, you can move from screen to screen like this:
Get.off(() => [targetscreen]());
Get.to(() => [targetscreen]());

Related

alert dialog pops up even when different route is called

I have a simple flutter app with two screens. On the first screen, i have an alert dialog that pops up every time a user visits the screen.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
void main() => runApp(const MyApp());
/// The route configuration.
final GoRouter _router = GoRouter(
routes: <RouteBase>[
GoRoute(
path: '/',
builder: (BuildContext context, GoRouterState state) {
return const HomeScreen();
},
routes: <RouteBase>[
GoRoute(
path: 'details',
builder: (BuildContext context, GoRouterState state) {
return const DetailsScreen();
},
),
],
),
],
);
/// The main app.
class MyApp extends StatelessWidget {
/// Constructs a [MyApp]
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp.router(
routeInformationProvider: _router.routeInformationProvider,
routeInformationParser: _router.routeInformationParser,
routerDelegate: _router.routerDelegate);
}
}
/// The home screen
class HomeScreen extends StatefulWidget {
/// Constructs a [HomeScreen]
const HomeScreen({Key? key}) : super(key: key);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
void initState() {
Timer(const Duration(seconds : 1), (() {
showDialog(
context: context,
builder: (context) {
return someDialogy();
});
print('i have been called forth');
}));
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Home Screen')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () => context.go('/details'),
child: const Text('Go to the Details screen'),
),
],
),
),
);
}
}
/// The details screen
class DetailsScreen extends StatelessWidget {
/// Constructs a [DetailsScreen]
const DetailsScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Details Screen')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <ElevatedButton>[
ElevatedButton(
onPressed: () => context.go('/'),
child: const Text('Go back to the Home screen'),
),
],
),
),
);
}
}
Widget someDialogy () {
return AlertDialog(
content: Center(
child: Text('data'),
),
);
}
When i try to navigate to my second screen using a hyperlink on web say http://localhost/secondscreen, the popup from my first screen shows up.
My guess is that in constructing the route stack, flutter calls the initstate in my first page which does show my popup. What is the best way to go around this while maintaining the popup that shows when my first page is called?
it would be helpful to show some mode code on this, like the somedialogy() method
anyways I suspect the issue might be with your routing solution,
try
onPressed: () {
// Navigate to the second route when the button is pressed
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
},
I think its all about Timer
try this:
Future.delayed(Duration(seconds: 1), () {
showDialog(
context: context,
builder: (context) {
return someDialogy();
});});
read this for more about Timer Understanding Flutter’s Timer class and Timer.periodic
and this 2 Types of Flutter Delay Widgets

restorablePush then pushAndRemoveUntil results in error (flutter)

What I want to achieve:
Screen 1 is the initial screen, and goes to Screen 2 (via restorablePush)
Screen 2 is a restorable page, and goes to Screen 3 (via restorablePush)
Screen 3 is a restorable page, and goes back to Screen 1 (via pushAndRemoveUntil)
The restoring stuff works fine, but when I go back to Screen 1 from Screen 3 then kill the app and reopen it, I get this failed assertion error:
_history.isNotEmpty:
All routes returned by onGenerateInitialRoutes are not restorable.
Please make sure that all routes returned by onGenerateInitialRoutes
have their RouteSettings defined with names that are defined in the
app's routes table.
I've look at onGeneralInitialRoutes but I can't figure out how to solve this. I also tried doing everything with named routes, but it didn't change anything.
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: Screen1(),
restorationScopeId: 'root',
);
}
}
class Screen1 extends StatefulWidget {
const Screen1({Key? key}) : super(key: key);
#override
State<Screen1> createState() => _Screen1State();
}
class _Screen1State extends State<Screen1> {
static Route<void> _myRouteBuilder(BuildContext context, Object? arguments) {
return MaterialPageRoute<void>(
builder: (BuildContext context) => const Screen2(),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: TextButton(
onPressed: () {
Navigator.restorablePush(context, _myRouteBuilder);
},
child: const Text('Go to Screen 2')),
),
);
}
}
class Screen2 extends StatefulWidget {
const Screen2({Key? key}) : super(key: key);
#override
State<Screen2> createState() => _Screen2State();
}
class _Screen2State extends State<Screen2> {
static Route<void> _myRouteBuilder(BuildContext context, Object? arguments) {
return MaterialPageRoute<void>(
builder: (BuildContext context) => const Screen3(),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Screen 2')),
body: Center(
child: TextButton(
onPressed: () => Navigator.restorablePush(context, _myRouteBuilder),
child: const Text('Go to Screen 3'),
)));
}
}
class Screen3 extends StatelessWidget {
const Screen3({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Screen 3')),
body: Center(
child: TextButton(
onPressed: () => Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => const Screen1()),
((route) => false)),
child: const Text('Go back to Screen 1'),
),
));
}
}

pushReplacementNamed doesn't replace it just pushes on top if coming from an AlertDialog

Here's the code:
3 FILES home, main, and screen1
MAIN:
import 'package:flutter/material.dart';
import 'home.dart';
import 'screen1.dart';
void main() {
runApp(MaterialApp(
home: Home(),
routes:
{
'/home' : (context) => Home(),
'/screen1': (context) => Screen1()
},
));
}
HOME:
import 'package:flutter/material.dart';
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: (){Navigator.pushReplacementNamed(context, '/screen1');},
child: Text('screen 1'),
),
),
);
}
}
screen1:
import 'package:flutter/material.dart';
Widget homeDialog(BuildContext context){
return AlertDialog(
title: const Text('Do you want to exit'),
actions: [
ElevatedButton(
child: const Text('No'),
onPressed: (){
Navigator.pop(context);
},
),
ElevatedButton(
child: const Text('Yes'),
onPressed: (){
Navigator.pushReplacementNamed(context, '/home');
},
),
],
);
}
class Screen1 extends StatefulWidget {
const Screen1({Key? key}) : super(key: key);
#override
State<Screen1> createState() => _Screen1State();
}
class _Screen1State extends State<Screen1> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text('screen 1'),
leading: GestureDetector(
onTap: (){showDialog(context: context, builder: homeDialog);},
child: Icon(Icons.home)
),
),
);
}
}
This happens because showDialog(AlertDialog(...)) is itself going to be pushed as a new route. So, when doing Navigator.pushReplacementNamed inside the alert it is going to replace the alert itself, not the previous screen. That's why Home and Screen1 got stacked on each other.
To solve this problem an AlertDialog should only return by a Navigator.pop(context, result) passing the result as an argument of it. The sources are going to be the following:
AlertDialog
Widget homeDialog(BuildContext context) {
return AlertDialog(
title: const Text('Do you want to exit'),
actions: [
ElevatedButton(
child: const Text('No'),
onPressed: () => Navigator.pop(context, false),
),
ElevatedButton(
child: const Text('Yes'),
onPressed: () => Navigator.pop(context, true),
),
],
);
}
Screen1
class Screen1 extends StatefulWidget {
const Screen1({Key? key}) : super(key: key);
#override
State<Screen1> createState() => _Screen1State();
}
class _Screen1State extends State<Screen1> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text('screen 1'),
leading: GestureDetector(
onTap: () async {
bool? yes =
await showDialog<bool>(context: context, builder: homeDialog);
// `mounted` checks if this screen hasn't been disposed already.
if (mounted) {
if (yes == true) {
Navigator.pushReplacementNamed(context, '/home');
} else {
Navigator.pop(context);
}
}
},
child: Icon(Icons.home)),
),
);
}
}

Flutter How does flutter implement partial-routing (partial-view)?

When push to SecondPage page:
I press the physical button to go back and it will go back to the desktop,
When I click the pop in second page button, it returns to the FirstPage page.
How can I do it so that when I press the physical button, I also go back to the FirstPage?
And after I click pop in first page, the body section will have nothing.
Is this a bug or?
Is there any other better way to implement partial-routing (partial-view)?, like a folder, pressing the return key can go back to the previous folder?
import 'package:flutter/material.dart';
class FlutterTest extends StatelessWidget {
const FlutterTest({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: Navigator(
initialRoute: '/',
onGenerateRoute: (rs) {
return MaterialPageRoute(builder: (ctx) => const FirstPage());
},
),
),
);
}
}
class FirstPage extends StatelessWidget {
const FirstPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Column(
children: [
const Text('this first page'),
TextButton(
child: const Text('pop in first page'),
onPressed: () {
Navigator.pop(context);
},
),
TextButton(
child: const Text('push second page'),
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (ctx) => const SecondPage()));
},
),
],
);
}
}
class SecondPage extends StatelessWidget {
const SecondPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Column(
children: [
const Text('this second page'),
TextButton(
child: const Text('pop in second page'),
onPressed: () {
Navigator.pop(context);
},
),
],
);
}
}

How can i pass parameters in flutter if the user goes back with the arrow?

I know that if you had a raiseButton you can do
Navigation .... .pop(value);
But what happens if the user goes back and i want to update the value, because result will be null
Navigator.push(context, MaterialPageRoute(builder: (context) {
return GalleryClassOne();
})).then((result) {
if (result != null) {
setState(() {
imagesClas1 = result;
});
}
});
You can override the back button behavior with WillPopScope widget. And manually pop with the data you need. Here is the code:
import 'package:flutter/material.dart';
void main() async {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Navigator(
onGenerateRoute: (settings) => MaterialPageRoute(
builder: (context) => MyHomePage(),
),
),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
void _onButtonPressed() {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => OtherPage()))
.then((value) {
print("returned: $value");
if (value != null) {
setState(() {
// ...
});
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Demo")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text("Open another screen"),
onPressed: _onButtonPressed),
],
),
),
);
}
}
class OtherPage extends StatelessWidget {
OtherPage({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
// here you can return anything you need ...
Navigator.of(context).pop("my value");
// cancel default behaviour
return false;
},
child: Scaffold(
appBar: AppBar(title: Text("Other page")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Click on return button'),
],
),
), // This trailing comma makes auto-formatting nicer for build methods.
),
);
}
}
You should return your data at a variable like this
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => SelectionScreen()),
);
The result variable has your data.
for more info, have a look at the docs