Flutter Navigator.pop(context) returning a black screen
DartFlutterDart Problem Overview
My Flutter Project structure is like this
Main() //Run App with MaterialApp and Routes
L HomePage() //Default route (/), with BottomNavigation
L MoviesPage() //Default BottomNavigation Index and shows a list of movies form TMDB
L DetailsPage()
L SeriesPage()
L SupportPage()
After clicking on any movie it navigates forward to the DetailsPage() but when I call Navigator.pop from DetailsPage() it should go back to the previous screen but it doesn't.
The Navigator.canPop(context) return false But the hardware back button works absolutely fine, so how do I fix it?
main.dart
class BerryMain extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Inferno(
{
'/': (context, argumets) => HomePage(),
'/detailspage': (context, arguments) => DetailsPage(arguments),
},
).home(context),
);
}
}
homepage
class HomePage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _HomePageState();
}
}
class _HomePageState extends State<HomePage> {
int _currentIndex = 0;
final List<Widget> _childnav = [MoviesPage(), SeriesPage(), SupportPage()];
void onTabPressed(...)
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('...'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: () {},
)
],
),
body: _childnav[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
onTap: onTabPressed,
currentIndex: _currentIndex, //this property defines current active tab
items: [
BottomNavigationBarItem(
icon: Icon(Icons.movie), title: Text('Movies')),
BottomNavigationBarItem(icon: Icon(Icons.tv), title: Text('Series')),
BottomNavigationBarItem(icon: Icon(Icons.help), title: Text('Help'))
],
),
);
}
}
MoviesPage
//Inside ListView Builder
Virgil.pushNamed(context, '/detailspage', arguments: args);
DetailsPage
//Inside MaterialApp > Scaffold > SliverAppbar > BackButton
Navigator.pop(context)
I'm using Virgil but I don't think it is the problem.
Dart Solutions
Solution 1 - Dart
This can happen if your MoviesPage
has another MaterialApp
widget. Most of the time you want to use Scaffold
as a top widget for a new page/screen, but if you accidentally use MaterialApp
instead, nothing warns you.
What happens, is that MaterialApp
creates a new Navigator
, so if you switch from one page with MaterialApp
to another, you now have two Navigators in the widget tree.
The call Navigator.of(context)
looks for the closest Navigator, so it'll use the one, newly created in your MoviesPage
. As the history of your route transitions is stored in a first Navigator, this one can't pop back – it has empty route history.
Hence, the black screen.
Long story short, to fix this, just use Scaffold
as a top widget instead of MaterialApp
in all nested screens.
Solution 2 - Dart
I had similar issues while poping back views, the way I fixed was instead of Navigator.of(context).pop();
I use Navigator.of(context).maybePop();
.
No more black screens after that.
Solution 3 - Dart
Just add optionally param rootNavigator: true
:
Sample:
Navigator.of(context, rootNavigator: true).pop(context);
Edit: In some cases, this solution may not resolve your issue. Please make sure that there is only one MaterialApp
widget in your app for all Pages.
Solution 4 - Dart
I resolve it using this code:
Navigator.pushReplacementNamed(context, '/route');
Solution 5 - Dart
Workaround is SystemNavigator.pop();
refer from this link
Solution 6 - Dart
I had a very similar problem and my solution was to pass BuildContext context from the created StatelessWidget to a global variable and pop that context from the global variable. So...
var globalContext; // Declare global variable to store context from StatelessWidget
class SecondScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
globalContext = context; // globalContext receives context from StetelessWidget.
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
canvasColor: Colors.transparent,
primarySwatch: Colors.blue,
),
home: SecondScreenPage(title: 'SECOND SCREEN'),
);
}
}
class SecondScreenPage extends StatefulWidget {
SecondScreenPage({Key key, this.title}) : super(key: key);
final String title;
@override
_SecondScreenPageState createState() => _SecondScreenPageState();
}
class _SecondScreenPageState extends State<SecondScreenPage>() {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Screen"),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.pop(globalContext), // POPPING globalContext
)
),
...
}
Now I don't get a black screen and I'm at my first page as if I had clicked on Android's back button. =)
I don't know if that is a good practice. If anyone knows a way to do that "more correctly", please feel free to answer.
Solution 7 - Dart
I also faced that problem and Still i was getting black screen after trying all of those previous answers.I do not have any idea about MaterialApp or Scafold reason because my application main.dart was only using MaterialApp, So Scafold solution did not work for me.Now what Solved for me.
POP BACK CODE
Navigator.of(context, rootNavigator: true).pop(context)
CODE THAT DID NOT WORK
Navigator.pushReplacement(context,CupertinoPageRoute(fullscreenDialog: false,builder: (context) => ChildClass())),
CODE THAT WORKED
Navigator.push(context,MaterialPageRoute(builder: (context) => ChildClass())
Solution 8 - Dart
Flutter App should have only 1 MaterialApp Why??? It is a core component that give access to all other elements
Technically thinking Material App contains App Title and a Home Screen widget
Here is my implementation
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'First Flutter App',
home: FirstActivity());
}
}
class FirstActivity extends StatefulWidget {
@override
_FirstActivityState createState() {
return _FirstActivityState();
}
}
class _FirstActivityState extends State<FirstActivity> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Activity'),
),
body: Center(
child: RaisedButton(
child: Text('Move Forward'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondActivity()),
);
}),
),
);
}
}
class SecondActivity extends StatefulWidget {
@override
_SecondActivityState createState() {
return _SecondActivityState();
}
}
class _SecondActivityState extends State<SecondActivity> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Activity'),
),
body: Center(
child: RaisedButton(
child: Text('Move Back'),
onPressed: () {
Navigator.pop(context);
}),
),
);
}
}
Solution 9 - Dart
Maybe in detail screen you are use MaterialApp as a main widget you need to just remove MaterialApp and diractly return Scaffold and maybe your problem will solve this is work for me.
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(),
),
);
}
instead of
Widget build(BuildContext context) {
return Scaffold(
body: Container(),
);
}
Solution 10 - Dart
to get rid of black screen, you can also use below method with as many pop() you want
Navigator.of(context)..pop()..pop();
Solution 11 - Dart
According to this Answer I figured it out a way.
You should pass the MoviesPage
context to the DetailsPage
. And that context should be called in Navigator.pop(context);
for Example: FIRST SCREEN
class FirstScreen extends StatelessWidget {
final BuildContext context;
FirstScreen(this.context);///here u have to call the build Context of FirstScreen
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: FirstScreenScreen(this.context));
}
}
class FirstScreenScreen extends StatefulWidget {
final BuildContext context;
FirstScreenScreen(this.context);/// and here also.
@override
_FirstScreenState createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreenScreen> {
@override
Widget build(BuildContext context) {
return new Scaffold(
body: Container(
child: new RaisedButton(onPressed: (){
navigateAndDisplaySelection(context);
},
child: new Text('Go to SecondPage'),
),
),
);
}
}
SECOND SCREEN
class SecondScreen extends StatelessWidget {
final BuildContext context;
SecondScreen(this.context);///here u have to call the build Context of FirstScreen
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: SecondScreenScreen(this.context));
}
}
class SecondScreenScreen extends StatefulWidget {
final BuildContext context;
SecondScreenScreen(this.context);/// and here also.
@override
_SecondScreenState createState() => _SecondScreenState();
}
class _SecondScreenState extends State<SecondScreenScreen> {
@override
Widget build(BuildContext context) {
return new Scaffold(
body: Container(
child: new RaisedButton(onPressed: (){
Navigator.pop(widget.context);///this context is passed from firstScreen
},
child: new Text('Go Back'),
),
),
);
}
}
Pass Data & Return
if you want pass data and return, add a constructor with parameter in SecondScreen and
call setState in method Fisrtlike this:
navigateAndDisplaySelection(
BuildContext context) async {
// Navigator.push returns a Future that will complete after we call
// Navigator.pop on the Second Screen!
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => new SecondScreen(context)),
);
setState(() {
/// the passed value data will change here, when you change in second screen
});
}
Solution 12 - Dart
I would like to share my experience in this, as I had the same issue.
Basically, pop
from empty screen stack is the major cause of this issue.
In my case, I was doing a periodic operation (reading some data from the camera) on scanner_screen (which was pushed to the stack by a button on my main_screen), when the camera finds a specific text, I call pop
. The issue was that the camera was reading too fast, and thus I pop
ped more than once, which means popping from an empty stack.
At first I though that popping is fast enough to call dispose on my scanner_screen to stop calling the periodic operation that keeps popping, but it was not. That is why I needed to make sure that periodic operation is stopped manually before popping from the screen stack.
I hope that may help somebody.
Solution 13 - Dart
Check your Navigator.push
code
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (context) => Nextscreen()));
if you use .pushReplacement
you cannot go back, it means you cannot use Navigator.pop(context)
.
otherwise, if you used
Navigator.push(context, MaterialPageRoute(builder: (context) => ListScreen(),),);
Kindly use this to get rid of the problem.
Navigator.of(context, rootNavigator: true).pop(context);
Solution 14 - Dart
-
Import page where you want to go.
-
Use Class of that
Page-Ex.Appointment
Navigator.push(context,new MaterialPageRoute(builder: (context)=> new Appointment() ),);
3. Remove Push name from Navigator
Solution 15 - Dart
This behaviour also appears when the initialRoute
is removed, something that can happen if you navigate to your first child by using:
Navigator.popAndPushNamed('...')
The solution is clearly simple tho, just use pushNamed
instead.
Solution 16 - Dart
Before navigating to another screen use Navigator.pop(context)
.
Example:
Navigator.pop(context),
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(uilder: (_) => GoogleMapScreenRemasterd()),
(Route<dynamic> route) => false),
Solution 17 - Dart
this work for me, i think it's the better solution.
WidgetsBinding.instance.addPostFrameCallback((_) {
Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => Menu()));
}),
Solution 18 - Dart
i have same issue like returning same screen return black screen
void main() async {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return GetMaterialApp(home: Todo());
}
}
class Todo extends StatefulWidget {
const Todo({Key key}) : super(key: key);
@override
_TodoState createState() => _TodoState();
}
class _TodoState extends State<Todo> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: RaisedButton(onPressed: (){
//print(controler.text);
//Navigator.push(context,MaterialPageRoute(builder: (context) => Todo("viral")));
//_sendDataBack(context);
Get.to(()=>Test());
},child: Text("submit"),),
) ;
}
}
other class
class Test extends StatefulWidget {
const Test({Key key}) : super(key: key);
@override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: RaisedButton(onPressed: (){
Get.to(()=>MyApp());
},child: Text("submit"),),
) ;
}
}
and then i check my code and realize that i am passing wrong class i have to return class that have my widget tree so replace Myapp() to Todo() like below and that fix my issue
class Test extends StatefulWidget {
const Test({Key key}) : super(key: key);
@override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: RaisedButton(onPressed: (){
Get.to(()=>MyApp());
},child: Text("submit"),),
) ;
}
}
Solution 19 - Dart
Use Navigator.pushNamed
instead of Navigator.pushReplacementNamed
Solution 20 - Dart
This is a common problem. These are just simple Issues. This happens when you push New screen and there also MaterialApp()
widget.
Solution 21 - Dart
This solution may be help others to avoid black screens. As it helps me.
if(Navigator.canPop(context)){
Navigator.of(context).pop();
}else{
SystemNavigator.pop();
}