Provider: create new model object per each sequence of pages - flutter

I am new to Provider. I am trying to use the provider model across multiple pages.
I have 2 sequence of pages. In the first sequence, there is only one page IncrementerPage, which will just increment the count. In the second sequence, there is an OptionsPage, which will display the count value and has 2 option buttons(Increment & Decrement). By clicking these buttons will navigate to corrensponding pages IncrementerPage & DecrementerPage to increment & decrement the count.
Note: In sequence1 and sequence2, the count should always start from zero.
This is what I done.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Home Page"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ChangeNotifierProvider<CounterModel>(
create: (context) => CounterModel(),
child: RaisedButton(
child: Text("Sequence1"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => IncrementerPage(),
),
);
},
),
),
ChangeNotifierProvider<CounterModel>(
create: (context) => CounterModel(),
child: RaisedButton(
child: Text("Sequence2"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => OptionsPage(),
),
);
},
),
),
],
),
),
);
}
}
class OptionsPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Consumer<CounterModel>(
builder: (context, model, child) {
return Text("Count: ${model.count}");
},
),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text("Increment"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => IncrementerPage(),
),
);
},
),
RaisedButton(
child: Text("Decrement"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DecrementerPage(),
),
);
},
),
],
),
),
);
}
}
class IncrementerPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Incrementor"),
),
body: Center(
child: Consumer<CounterModel>(
builder: (context, model, child) {
return Text(
'${model.count}',
style: const TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
color: Colors.black54,
),
);
},
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Provider.of<CounterModel>(context, listen: false).increment();
},
),
);
}
}
class DecrementerPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Decrementer"),
),
body: Center(
child: Consumer<CounterModel>(
builder: (context, model, child) {
return Text(
'${model.count}',
style: const TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
color: Colors.black54,
),
);
},
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.remove),
onPressed: () {
Provider.of<CounterModel>(context, listen: false).decrement();
},
),
);
}
}
class CounterModel extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
void decrement() {
_count--;
notifyListeners();
}
}
But I am getting this error:
Could not find the correct Provider<CounterModel> above this Consumer<CounterModel> Widget
By moving ChangeNotifierProvider<CounterModel> outside the MaterialApp fixed the error. But both sequence of pages seems to be using the same counter variable (or model like global). So how to pass different model object per each sequence of pages? or is there any better way to do this?.

Probably the following code is causing the exception:
floatingActionButton: FloatingActionButton(
child: Icon(Icons.remove),
onPressed: () {
Provider.of<CounterModel>(context, listen: false).decrement();
},
),
As you can see, the ChangeNotifierProvider for CounterModel is Wrapped around widgets RaisedButton() for sequence 1 and 2 only.
Which are under the body parameter. While the floatingActionButton a colleague parameter for body.
Meaning the Provider.of<CounterModel> can not find the Provider from it's parent widgets.
What you can do is, Move the ChangeNotifierProvider code to cover HomePage and remove every other ChangeNotifierProvider code for CounterModel in the app.

Related

Plutogrid show dialog after iconbutton pressed

how can I show an dialog widget after a click on an Iconbutton in a plutogrid cell?
This is my code in der renderer for the plutogrid cell:
return Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
IconButton(
icon: Icon(
Auswahl,
),
onPressed: () {}, => here I want to show a dialog widged...
iconSize: 18,
color: Colors.black,
),
]);
And here is the code for the dialog:
void _selectDialog() async {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Add Info'),
content: setupSelectDialoagContainer(),
);
});
}
I tried to call _selectDialog(), but I got the error:
The instance member '_selectDialog' can't be accessed in an initializer.
I don't know why you faced this error, this is my code showing the same dialog as yours and it's working.
Here's the code:
class Demo extends StatefulWidget {
const Demo({super.key});
#override
State<Demo> createState() => _DemoState();
}
class _DemoState extends State<Demo> {
void _selectDialog() async {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Add Info'),
// content: setupSelectDialoagContainer(),
);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: [
Center(
child: IconButton(
onPressed: () {
_selectDialog();
},
icon: Icon(Icons.abc),
),
)
],
),
);
}
}

how to refresh Old screen when update second using inherited widget in flutter

I have created a simple app using InheritedWidget, just a counter app...
I have just four files:
main.dart.
CommonScreenProvider.dart.
first_screen.dart.
second_screen.dart.
the problem here when I am trying to use the counter function in in the second_screen and go back to the first_screen I can not find any updates till I use the counter but while I use counter in first screen I found the updated value in the second screen without problem, I think there's missing a refresh function or something?
Here's the code implementation...
CommonScreenProvider
import 'package:flutter/material.dart';
class CommonScreenProvider extends InheritedWidget {
num counter = 0;
Widget child;
CommonScreenProvider({#required this.child});
#override
bool updateShouldNotify(covariant CommonScreenProvider oldWidget) {
return oldWidget.counter != counter;
}
static CommonScreenProvider of(BuildContext ctx) =>
ctx.dependOnInheritedWidgetOfExactType();
}
first_screen
import 'package:flutter/material.dart';
import 'package:statemanagementtest/second_screen.dart';
import 'commom_screen_provider.dart';
class FirstScreen extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
var provider = CommonScreenProvider.of(ctx);
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.send_to_mobile),
onPressed: () {
Navigator.of(ctx).push(
MaterialPageRoute(
builder: (ctx) => SecondScreen(),
),
);
},
),
],
title: Text('My Counter App'),
),
body: Center(
child: StatefulBuilder(builder: (ctx, StateSetter setState) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: Icon(Icons.remove),
iconSize: 50,
onPressed: () {
setState(() {
provider.counter--;
});
},
),
Text(
'${provider.counter}',
style: Theme.of(ctx).textTheme.display1,
),
IconButton(
icon: Icon(Icons.add),
iconSize: 50,
onPressed: () {
setState(() {
provider.counter++;
});
},
),
],
);
}),
),
);
}
}
second_screen
import 'package:flutter/material.dart';
import 'commom_screen_provider.dart';
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
var pSecond = CommonScreenProvider.of(ctx);
return Scaffold(
appBar: AppBar(
title: Text('My Counter App'),
),
body: Center(
child: StatefulBuilder(builder: (ctx, StateSetter setState) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: Icon(Icons.remove),
iconSize: 50,
onPressed: () {
setState(() {
pSecond.counter--;
});
},
),
Text(
'${pSecond.counter}',
style: Theme.of(ctx).textTheme.display1,
),
IconButton(
icon: Icon(Icons.add),
iconSize: 50,
onPressed: () {
setState(() {
pSecond.counter++;
});
},
),
],
);
}),
),
);
}
}
main.dart
import 'package:flutter/material.dart';
import 'package:statemanagementtest/commom_screen_provider.dart';
import 'package:statemanagementtest/first_screen.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
return CommonScreenProvider(
child: MaterialApp(
home: FirstScreen(),
),
);
}
}
You can copy paste run full code below
Quick fix is move StatefulBuilder up and await Navigator.of(ctx).push then call setState
code snippet
class FirstScreen extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
var provider = CommonScreenProvider.of(ctx);
return StatefulBuilder(builder: (ctx, StateSetter setState) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.send_to_mobile),
onPressed: () async {
await Navigator.of(ctx).push(
MaterialPageRoute(
builder: (ctx) => SecondScreen(),
),
);
setState(() {});
working demo
full code
import 'package:flutter/material.dart';
class CommonScreenProvider extends InheritedWidget {
num counter = 0;
Widget child;
CommonScreenProvider({#required this.child});
#override
bool updateShouldNotify(covariant CommonScreenProvider oldWidget) {
return oldWidget.counter != counter;
}
static CommonScreenProvider of(BuildContext ctx) =>
ctx.dependOnInheritedWidgetOfExactType();
}
class FirstScreen extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
var provider = CommonScreenProvider.of(ctx);
return StatefulBuilder(builder: (ctx, StateSetter setState) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.send_to_mobile),
onPressed: () async {
await Navigator.of(ctx).push(
MaterialPageRoute(
builder: (ctx) => SecondScreen(),
),
);
setState(() {});
},
),
],
title: Text('My Counter App'),
),
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: Icon(Icons.remove),
iconSize: 50,
onPressed: () {
setState(() {
provider.counter--;
});
},
),
Text(
'${provider.counter}',
style: Theme.of(ctx).textTheme.display1,
),
IconButton(
icon: Icon(Icons.add),
iconSize: 50,
onPressed: () {
setState(() {
provider.counter++;
});
},
),
],
)),
);
});
}
}
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
var pSecond = CommonScreenProvider.of(ctx);
return Scaffold(
appBar: AppBar(
title: Text('My Counter App'),
),
body: Center(
child: StatefulBuilder(builder: (ctx, StateSetter setState) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
icon: Icon(Icons.remove),
iconSize: 50,
onPressed: () {
setState(() {
pSecond.counter--;
});
},
),
Text(
'${pSecond.counter}',
style: Theme.of(ctx).textTheme.display1,
),
IconButton(
icon: Icon(Icons.add),
iconSize: 50,
onPressed: () {
setState(() {
pSecond.counter++;
});
},
),
],
);
}),
),
);
}
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext ctx) {
return CommonScreenProvider(
child: MaterialApp(
home: FirstScreen(),
),
);
}
}

Flutter showDialog not working on a simple test

I am trying flutter and have problems in making a simple showdialog work. I tried a simple test with one button:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter Test',
home: Scaffold(
appBar: AppBar(
backgroundColor: Colors.teal,
title: Text('Flutter'),
),
body: Center(
child: ListView(
padding: EdgeInsets.all(8),
children: <Widget>[
Container(
child: RaisedButton(
child: Text('My Button'),
onPressed: () => {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
title: Text('Test'),
content: Text('Dialog content'),
);
},
),
},
color: Colors.cyan,
textColor: Colors.white,
),
),
],
),
),
),
);
}
}
I expect the alert to pop on button tap. What am I missing? I also tried it with the showdialog in a separate custom function call, same result.
You need to use the showDialog method provided by Flutter, as seen on the example here. Check my example below with your button but using the showDialog method:
class DialogIssue extends StatefulWidget {
#override
_DialogIssueState createState() => _DialogIssueState();
}
class _DialogIssueState extends State<DialogIssue> {
#override
Widget build(BuildContext context) {
return Center(
child: RaisedButton(
child: Text('My Button'),
onPressed: () => _confirmDialog(),
color: Colors.cyan,
textColor: Colors.white,
),
);
}
Future<void> _confirmDialog() async {
switch (await showDialog<bool>(
context: context,
builder: (BuildContext context) {
return SimpleDialog(
title: const Text('True or false'),
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
SimpleDialogOption(
onPressed: () { Navigator.pop(context, true); },
child: const Text('Confirm',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
SimpleDialogOption(
onPressed: () { Navigator.pop(context, false); },
child: const Text('Cancel'),
),
],
),
],
);
}
)){
case true:
print('Confirmed');
break;
case false:
print('Canceled');
break;
default:
print('Canceled');
}
}
}
It can be done in a StatelessWidget, like in this DartPad pad.
Sidenote: I've had to use a Builder because the context in MyApp's build method doesn't have a MaterialApp ancestor.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
showAppDialog(BuildContext context) {
print("Showing app dialog");
showDialog(context: context,
builder: (context) {
return AlertDialog(
title: const Text(
"This is a dialog that works.",
),
icon: const Icon(Icons.delete),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text("OK"),
),
],
);
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(body: SafeArea(child: Builder(
builder: (context) {
return TextButton(child: Text("Show dialog"), onPressed: () => showAppDialog(context),);
}
))),
);
}
}
PS: You're already using showDialog, why does this answer suggest you to do that 🤔.

What is the use of `rootNavigator` in Navigator.of(context, rootNavigator: true).push();

What's the difference between
Navigator.of(context).pushNamed("/route");
and
Navigator.of(context, rootNavigator: true).pushNamed("/route");
More importantly, what's the use of setting rootNavigator: true on Navigator class, I read docs but they aren't quite clear. Can anyone explain the difference properly?
You can copy paste run full code below
There is a root Navigator above tab navigation
This demo shows open(Navigator.push) a full screen dialog (fullscreenDialog: true) with rootNavigator true/false
picture
rootNavigator = true , fullscreenDialog take all screen and above tab
rootNavigator = false, fullscreenDialog take tab size and inside tab, you can switch between Home and Support tab and see fullscreenDialog is still there
working demo
code snippet
Center(
child: CupertinoButton(
child: const Text(
'Push rootNavigator true',
),
onPressed: () {
Navigator.of(context, rootNavigator: true).push(
CupertinoPageRoute<bool>(
fullscreenDialog: true,
builder: (BuildContext context) => Tab3Dialog(),
),
);
},
),
),
Center(
child: CupertinoButton(
child: const Text(
'Push rootNavigator false',
),
onPressed: () {
Navigator.of(context, rootNavigator: false).push(
CupertinoPageRoute<bool>(
fullscreenDialog: true,
builder: (BuildContext context) => Tab3Dialog(),
),
);
},
),
),
full code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: PawzHome(),
);
}
}
class PawzHome extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CupertinoTabScaffold(
tabBar: CupertinoTabBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.home),
title: Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(CupertinoIcons.conversation_bubble),
title: Text('Support'),
),
],
),
tabBuilder: (BuildContext context, int index) {
switch (index) {
case 0:
return CupertinoTabView(
builder: (BuildContext context) {
return CupertinoDemoTab1();
},
defaultTitle: 'Colors',
);
break;
case 1:
return CupertinoTabView(
builder: (BuildContext context) => CupertinoDemoTab2(),
defaultTitle: 'Support Chat',
);
break;
}
return null;
},
);
}
}
class CupertinoDemoTab1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: CustomScrollView(
slivers: <Widget>[
CupertinoSliverNavigationBar(),
SliverList(
delegate: SliverChildListDelegate([Tab1RowItem()]),
),
],
),
);
}
}
class Tab1RowItem extends StatelessWidget {
#override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Navigator.of(context).push(CupertinoPageRoute<void>(
title: "Click me",
builder: (BuildContext context) => Tab1ItemPage(),
));
},
child: Padding(padding: EdgeInsets.all(10.0), child: Text("Click me")),
);
}
}
class Tab1ItemPage extends StatelessWidget {
#override
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(),
child: Container(
child: Column(
children: <Widget>[
SizedBox(height: 100,),
Center(
child: CupertinoButton(
child: const Text(
'Push rootNavigator true',
),
onPressed: () {
Navigator.of(context, rootNavigator: true).push(
CupertinoPageRoute<bool>(
fullscreenDialog: true,
builder: (BuildContext context) => Tab3Dialog(),
),
);
},
),
),
Center(
child: CupertinoButton(
child: const Text(
'Push rootNavigator false',
),
onPressed: () {
Navigator.of(context, rootNavigator: false).push(
CupertinoPageRoute<bool>(
fullscreenDialog: true,
builder: (BuildContext context) => Tab3Dialog(),
),
);
},
),
),
],
),
));
}
}
class CupertinoDemoTab2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(),
child: Container(
child: Center(
child: Text("Tab 2"),
),
));
}
}
class Tab3Dialog extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
leading: CupertinoButton(
onPressed: () {
Navigator.of(context).pop(false);
},
child: Text("Ok"),
),
),
child: Center(
child: CupertinoButton(
color: CupertinoColors.activeBlue,
child: const Text('Sign in'),
onPressed: () {
Navigator.pop(context);
},
),
),
);
}
}
If your app has nested navigators this parameter comes in handy when you want to call the root navigator not it's nested navigators ... please consider the image bellow ... in this example we are inside the page 2 and we want the page 3 to be the rootNavigator's child (because for example we want to ignore the bottomNavigationBar that is in MainPage)... in this example if you don't set the rootNavigator = true and you push the page 3 it will be the nestedNavigator's child (So the BottomNavigationBar of the MainPage's will be still visible).

Flutter Navigator.popUntil failed assertion _debugLocked. What's wrong?

^ ^ ^^ ^ NO! THIS QUESTION DOES NOT HAVE AN ANSWER THERE! ^ ^ ^ ^ ^ ^
I'm having problems with Navigator.popUntil. I wrote a small demo app to show what's happening. Before I post this as a bug, am I using popUntil wrong??
call to popUntil displays
It looks like something is locking up the Navigator (setting _debugLocked) and not releasing it.
main.dart below : (can just be pasted into the Flutter demo app)
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Routing Test Page'),
onGenerateRoute: (RouteSettings settings) {
switch (settings.name) {
case '/':
return MaterialPageRoute(
builder: (_) => MyHomePage(title: 'Home Page',),
settings: settings,
);
case '/home':
return MaterialPageRoute(
builder: (_) => MyHomePage(title: 'Home Page',),
settings: settings,
);
case '/middlepage':
return MaterialPageRoute(
builder: (_) => MiddlePage(),
settings: settings,
);
case '/bottompage':
return MaterialPageRoute(
builder: (_) => BottomBage(),
settings: settings,
);
default:
return null;
}
},
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Home Page',
),
OutlineButton(
child: Text('push MiddlePage()'),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (context) => (MiddlePage())),
),
),
OutlineButton(
child: Text('pushNamed ''/middlepage'''),
onPressed: () => Navigator.pushNamed(context, '/middlepage'),
),
],
),
),
);
}
}
class MiddlePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Middle Page'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Middle Page',style: TextStyle(fontWeight: FontWeight.bold)
),
OutlineButton(
child: Text('push BottomPage()'),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (context) => (BottomBage())),
),
),
OutlineButton(
child: Text('pushNamed ''/bottompage'''),
onPressed: () => Navigator.pushNamed(context, '/bottompage'),
),
OutlineButton(
child: Text('pop'), onPressed: () => Navigator.pop(context)),
OutlineButton(
child: Text('popUntil ''/home'''),
onPressed: () =>
Navigator.popUntil(context, ModalRoute.withName('/home'))),
],
),
),
);
}
}
class BottomBage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Bottom page'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Bottom Page', style: TextStyle(fontWeight: FontWeight.bold),
),
OutlineButton(
child: Text('push ''home'''),
onPressed: () =>
Navigator.pushNamed(context, '/home'),
),
OutlineButton(
child: Text('pop'),
onPressed: () =>
Navigator.pop(context)),
OutlineButton(
child: Text('popUntil ''/home'''),
onPressed: () =>
Navigator.popUntil(context, ModalRoute.withName('/home')),
),
OutlineButton(
child: Text('popUntil ''/home'' (with Are You Sure box)) '),
onPressed: () async {
try {
if (await _areYouSureDialog(context)) {
Navigator.popUntil(context, ModalRoute.withName('/home'));
}
} catch (e) {
debugPrint("exception: $e");
}
},
),
],
),
),
);
}
}
Future<bool> _areYouSureDialog(BuildContext context) async {
return await showDialog<bool>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Pop back?'),
content: const Text('Are you sure?'),
actions: <Widget>[
FlatButton(
child: const Text('YES'),
onPressed: () {
Navigator.of(context).pop(true);
},
),
FlatButton(
child: const Text('NO'),
onPressed: () {
Navigator.of(context).pop(false);
},
),
],
);
},
) ??
false;
}
I recreated your case. Whenever we want to pop navigation to the home screen (root) from anywhere, there are couple of ways to do it as below:
1.Using .isFirst method:
Navigator.of(context).popUntil((route) => route.isFirst);
Using defaultRouteName:
Navigator.popUntil(context, ModalRoute.withName(Navigator.defaultRouteName));
By providing the context first, the route will ensure that the navigation will pop to the default always.
You can try with either approach. I tested at my end and it works well.
Hope this answers your question.