Reputation: 1411
I am new in Flutter and I am trying to receive data with a Dialog. When i click in textField the error of image2 appears...
show(BuildContext context){
var dialog = Dialog(
child: Container(
margin: EdgeInsets.all(8.0),
child: Form(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextFormField(
decoration: InputDecoration(
labelText: "Insira o número de telefone",
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(2.0)))),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("Cancelar")),
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("Aceitar"))
],
)
],
),
),
),
);
showDialog(context: context,builder: (context){
return dialog;
});
}
This is my code.
I/flutter (31032): Looking up a deactivated widget's ancestor is unsafe.
I/flutter (31032): At this point the state of the widget's element tree is no longer stable. To safely refer to a
I/flutter (31032): widget's ancestor in its dispose() method, save a reference to the ancestor by calling
I/flutter (31032): inheritFromWidgetOfExactType() in the widget's didChangeDependencies() method.
I/flutter (31032):
Upvotes: 131
Views: 258710
Reputation: 2386
in my case, i popped it before invoking callback:
onPressed: {
Navigator.pop(context);
widget.onAccept();
}
the fix:
onPressed: {
widget.onAccept();
// Call logic above before popping
Navigator.pop(context);
}
Upvotes: 0
Reputation: 1
you can work with it:
final GlobalKey<NavigatorState> navigatorKey =GlobalKey<NavigatorState();
Future<void> main() async {...}
put it all over the method hand. and then add it in the materialApp
return MaterialApp(
navigatorKey: navigatorKey,
and then use it from anywhere in the app
Upvotes: 0
Reputation: 1
I encountered the error 'Looking up a deactivated widget's ancestor is unsafe.' while working with GetX. Initially, I utilized the 'GetMaterialApp' widget in the main function to launch the app:
void main() => runApp(
DevicePreview(
enabled: true,
builder: (context) => GetMaterialApp(home: const MyApp()), // Wrap your app
),
);
However, after switching to the conventional MaterialApp, the issue was resolved:
void main() => runApp(
DevicePreview(
enabled: true,
builder: (context) => MaterialApp(home: const MyApp()), // Wrap your app
),
);
Upvotes: 0
Reputation: 1192
i get answer with this snippet :
@override
void didChangeDependencies() {
Navigator.of(context);
super.didChangeDependencies();
}
Upvotes: 2
Reputation: 101
First let's understand what the framework is saying:
Point - 1:
Looking up a deactivated widget's ancestor is unsafe. At this point the state of the widget's element tree is no longer stable.
This simply means that the widget(parent of Dialog) is no longer present in the widget tree and it can be confirmed by checking the result of context.mounted
property. This can be solved by providing a valid BuildContext
to the child just by wrapping the Dialog with a Builder
class. You can refer this answer to understand the significance of Builder
.
show(BuildContext context){
var dialog = Dialog(
child: Container(
margin: EdgeInsets.all(8.0),
child: Form(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextFormField(
decoration: InputDecoration(
labelText: "Insira o número de telefone",
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(2.0)))),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("Cancelar")),
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("Aceitar"))
],
)
],
),
),
),
);
showDialog(
context: context,
// Wrapping the clild widget (dialog) within a Builder class.
builder: (context) => Builder(
builder: (context) {
return dialog;
},
),
);
}
Point - 2:
To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling inheritFromWidgetOfExactType() in the widget's didChangeDependencies() method.
This simply asks us to save the context(reference to the parent widget) before it gets de-activated. The suggestions to use GlobalKey in the above answers simply does the same. As GlobalKey is unique throughout the application, the context is preserved. However, one can also save the context using state management.
Upvotes: 1
Reputation: 1994
I had the same bug, but in totally different context. I use Riverpod as a state manager, and I wanted to cancel a stream in StatefulWidget dispose method. It turned out that it caused this bug. What I had to do is to use Riverpod's onDispose
API.
ref.onDispose(() {
batteryStateSubscription.cancel();
});
A full example is shown in the documentation
Upvotes: 2
Reputation: 39
calling Navigator.pop(context) at the beginning of async function worked for me.
Upvotes: 1
Reputation: 41
Use this if You are using Stack in AlertDialog Not Closing on Navigator.of(context).pop();
late NavigatorState _navigator;
@override
void didChangeDependencies() {
_navigator = Navigator.of(context);
super.didChangeDependencies();
}
Use This
Positioned(right: 10.0,child: GestureDetector(
// behavior: HitTestBehavior.translucent,
onTap: () {
_navigator.pop(context);
},
child: Align(
alignment: Alignment.topRight,
child: CircleAvatar(
radius: 14.0,
backgroundColor: Colors.white,
child: Icon(Icons.close, color: black),
),
),
),
),
Upvotes: 4
Reputation: 31
In my case I was using a provider where I used a context as an argument to a function, the thing was that when I passed that page I did it with pushnamedAndRemove Until then on the next page I was trying to use a function where I required the above context, so the error was mine because it was trying to get a parameter that I destroyed earlier, for that reason it didn't work. So be careful if you are deleting old pages.
Upvotes: 0
Reputation: 2633
Though you got desired answer, just for better clarification for others I put my opinion here.
Reason : It is happend due to context mismatch issue. Your passing context to Navigator.of(context).pop() is not matching with your MainApp BuildContext.
Solution : There has 2 way
Below link I already mentioned how to solve this by passing actual context
https://stackoverflow.com/a/73543251/6109034
Upvotes: 1
Reputation: 115
before calling a dialog when a page is just loading, call it by adding SchedulerBinding to it, call it like this
SchedulerBinding.instance?.addPostFrameCallback((_) => showDialog( context: context, barrierDismissible: false, builder: (context) { return dialogBox(context, "Fetching account data", 'Profile page', DialogType.processing, function: () {}, dismissText: "", ); }));
Upvotes: 1
Reputation: 331
In my case i was calling
setState(() {
Navigator.pop(context);
});
Upvotes: -3
Reputation: 41
removing application from emulator and run below commands
flutter clean
flutter pub get
works for me
Upvotes: 2
Reputation: 1
first : declare a FormKey.
GlobalKey<FormState>myFormKey=GlobalKey<FormState>();
second : add the FormKey to your Form widget.
Form(
key:myFormKey,
child:child
)
Upvotes: -1
Reputation: 1354
declare dialog and set in initState
late Dialog dialog;
@override
void initState() {
super.initState();
dialog = Dialog(
...
);
}
Upvotes: 0
Reputation: 115
I simply solved this by wrapping the showDialog with a Builder widget, though for me the error came from a stream builder I simply wrap the stream builder with a builder widget and the remove the notify listeners from the a stream am calling in the stream builder, but in your case wrap the showDialog with a Builder widget and it will use the context from the builder, problem solved
Upvotes: -1
Reputation: 323
My problem was that I was using hot reload for pretty long time, I think at some point everything got messed up, doing a normal run of the app fixed the problem.
Upvotes: 8
Reputation: 1193
use this:
Navigator.of(context,rootNavigator: true).pop();
instead of
Navigator.of(context).pop();
Upvotes: 20
Reputation: 197
This might happen while you are popping from the context and trying to open new content on the context you are popping.
()async{
Navigator.of(context).pop();
_alertPopUp(); // shows a dialog
// might do some work after
}
if alert dialog is created on current context then it throws an error because context doesn't exist anymore
Upvotes: 10
Reputation: 1572
I got the same error when attempting to open a dialog and I found a solution here: github flutter issues. Specifically, I followed the poster's recommendation, which was to create a GlobalKey
and associate it with the Scaffold
widget, and use the context from that key when creating the dialog. In my case, I have a globally accessible object which holds the GlobalKey
:
MyGlobals myGlobals = MyGlobals();
class MyGlobals {
GlobalKey _scaffoldKey;
MyGlobals() {
_scaffoldKey = GlobalKey();
}
GlobalKey get scaffoldKey => _scaffoldKey;
}
In the Scaffold
widget constructor call:
Scaffold(
appBar: ...,
body: ...,
drawer: ...,
key: myGlobals.scaffoldKey,
)
And in the showDialog
call:
showDialog<String>(
barrierDismissible: ...,
builder: ...,
context: myGlobals.scaffoldKey.currentContext,
);
Upvotes: 28
Reputation: 2551
Declare a global variable
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
then register the key on your widget build's scaffold eg
@override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
...
then on the dialog
show(BuildContext context){
var dialog = Dialog(
child: Container(
margin: EdgeInsets.all(8.0),
child: Form(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextFormField(
decoration: InputDecoration(
labelText: "Insira o número de telefone",
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(2.0)))),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("Cancelar")),
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("Aceitar"))
],
)
],
),
),
),
);
Pass that scaffold context to the showDialog method
showDialog(context: _scaffoldKey.currentContext ,builder: (context){
return dialog;
});
}
Upvotes: 127
Reputation: 1622
Try This
Give different context name for dialog
showDialog(context: context,builder: (dialogContex){
return Dialog(
child: Container(
margin: EdgeInsets.all(8.0),
child: Form(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextFormField(
decoration: InputDecoration(
labelText: "Insira o número de telefone",
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(2.0)))),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(dialogContex).pop();
},
child: Text("Cancelar")),
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("Aceitar"))
],
)
],
),
),
),
);
});
Upvotes: 77
Reputation: 3530
Try this:
Future<AlertDialog> myDialog(BuildContext context) {
return showDialog<AlertDialog>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: Container(
margin: EdgeInsets.all(8.0),
child: Form(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextFormField(
decoration: InputDecoration(
labelText: "Insira o número de telefone",
border: OutlineInputBorder(
borderRadius:
BorderRadius.all(Radius.circular(2.0)))),
),
],
),
),
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("Cancelar")),
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("Aceitar"))
],
);
},
);
}
Upvotes: 0
Reputation: 17776
You’re trying to access a context that isn’t probably available. That happens because you’ve assigned your Dialog
to a var
and afterwards use a different context (the one from your dialog builder).
Either create your dialog directly after your return
in the builder or make it a method instead that returns a Dialog
and pass it a BuildContext
parameter.
Widget myDialog(BuildContext context) => Dialog(/*your dialog here*/);
This is also a more convenient Flutter practice. You should use methods that return widgets instead of assigning it to variables.
Upvotes: 21