【问题标题】:Flutter Navigator.pop(context) returning a black screenFlutter Navigator.pop(context) 返回黑屏
【发布时间】:2019-05-12 09:26:47
【问题描述】:

我的 Flutter Project 结构是这样的

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()

点击任何电影后,它会向前导航到 DetailsPage(),但是当我从 DetailsPage() 调用 Navigator.pop 时,它应该返回上一个屏幕,但它没有。

Navigator.canPop(context) return false 但是硬件后退按钮工作得很好,那我该如何解决呢?

ma​​in.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),
    );
  }
}

主页

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'))
        ],
      ),
    );
  }
}

电影页面

//Inside ListView Builder
Virgil.pushNamed(context, '/detailspage', arguments: args);

详情页面

//Inside MaterialApp > Scaffold > SliverAppbar > BackButton
Navigator.pop(context)

我正在使用Virgil,但我认为这不是问题。

【问题讨论】:

标签: dart flutter


【解决方案1】:

如果您的 MoviesPage 有另一个 MaterialApp 小部件,则可能会发生这种情况。大多数情况下,您希望将Scaffold 用作新页面/屏幕的顶部小部件,但如果您不小心使用了MaterialApp,则不会发出任何警告。

发生的情况是,MaterialApp 创建了一个新的Navigator,因此,如果您从一个带有MaterialApp 的页面切换到另一个页面,那么您现在在小部件树中有两个导航器。

调用Navigator.of(context) 会查找最近的导航器,因此它将使用在您的MoviesPage 中新创建的导航器。由于您的路线转换历史存储在第一个导航器中,因此该导航器无法弹回 - 它的路线历史为空。

因此,黑屏。

长话短说,要解决这个问题,只需在所有嵌套屏幕中使用 Scaffold 作为顶部小部件,而不是 MaterialApp

【讨论】:

  • %100 是对的。 MaterialApp 使应用成为丢失的路由。
  • 我只在 main.dart 中使用 MaterialApp,然后我也面临黑屏,同时使用 Navigator.push(context, MaterialPageRoute(builder: (context) { return VisitorsIN();}));
  • 应该有一个和一个 Material 应用程序。谢谢@divan
  • flutter.dev 上的教程展示了视图之间不同脚手架的使用:flutter.dev/docs/cookbook/navigation/named-routes
  • 这应该接受答案
【解决方案2】:

我在弹出视图时遇到了类似的问题,我修复的方法是使用 Navigator.of(context).maybePop(); 而不是 Navigator.of(context).pop();

之后不再出现黑屏。

【讨论】:

  • maybePop() 也会失败,您从第一个屏幕显示警报对话框。它只检查它是否可以弹出。如果您已经显示警报对话框,它将始终返回 yes 并弹出一个小部件。
  • 这不是清除导航堆栈的解决方案。
  • 这不起作用。
【解决方案3】:

只需添加可选参数rootNavigator: true: 示例:

Navigator.of(context, rootNavigator: true).pop(context);

编辑:在某些情况下,此解决方案可能无法解决您的问题。请确保您的应用中只有一个 MaterialApp 小部件适用于所有页面。

【讨论】:

  • 这个答案对我来说很重要
【解决方案4】:

我使用此代码解决它:

Navigator.pushReplacementNamed(context, '/route');

【讨论】:

    【解决方案5】:

    我有一个非常相似的问题,我的解决方案是将 BuildContext context 从创建的 StatelessWidget 传递到全局变量,然后从全局变量中弹出该上下文。所以...

    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
            )
          ),
      ...
    }
    

    现在我没有黑屏,而且我在第一页,就好像我点击了 Android 的后退按钮一样。 =)

    我不知道这是否是一个好习惯。如果有人知道“更正确”的方法,请随时回答。

    【讨论】:

    • 就像我说的,不一样。这是相似的。我遇到了导航弹出问题,也许我的解决方案(就我而言)可以帮助程序员解决他的问题。
    • 其实我要谢谢你。您的解决方案对我有帮助,因为我也遇到了黑屏。所以谢谢你。
    • 不客气。很高兴我的解决方案对您有所帮助。 :)
    【解决方案6】:

    解决方法是SystemNavigator.pop();refer from this link

    【讨论】:

    • 这实际上会退出应用程序。不是 OP 正在寻找的东西。
    • 这会完全关闭应用程序。
    【解决方案7】:

    我也遇到了这个问题,但在尝试了所有以前的答案后,我仍然出现黑屏。我对 MaterialApp 或 Scafold 原因一无所知,因为我的应用程序 main.dart 仅使用 MaterialApp,所以 Scafold 解决方案没有为我工作。现在为我解决了什么问题。

    弹回代码

    Navigator.of(context, rootNavigator: true).pop(context)
    

    不起作用的代码

     Navigator.pushReplacement(context,CupertinoPageRoute(fullscreenDialog: false,builder: (context) => ChildClass())),
    

    有效的代码

     Navigator.push(context,MaterialPageRoute(builder: (context) => ChildClass())
    

    【讨论】:

    • Navigator.of(context, rootNavigator: true).pop(context)为我工作。
    • 您的代码非常适合我,让我免于浪费时间。非常感谢。
    【解决方案8】:

    Flutter App 应该只有 1 个 MaterialApp 为什么??? 它是一个核心组件,可以访问所有其他元素

    具有技术思维的 Material App 包含 App Title 和一个主屏幕小部件

    这是我的实现

    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);
            }),
            ),
           );
         }
      }
    

    【讨论】:

      【解决方案9】:

      也许在详细屏幕中,您使用 MaterialApp 作为主要小部件,您只需删除 MaterialApp 并直接返回 Scaffold,也许您的问题会解决,这对我有用。

      Widget build(BuildContext context) {
          return MaterialApp(
            home: Scaffold(
             body: Container(),
           ),
          );
        }
      

      而不是

      Widget build(BuildContext context) {
       return Scaffold(
         body: Container(),
       );
      }
      

      【讨论】:

        【解决方案10】:

        根据这个Answer我想出了一个办法。

        您应该将MoviesPage 上下文传递给DetailsPage。应该在Navigator.pop(context);

        中调用该上下文

        例如: 首屏

        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'),
                    ),
                  ),
               );
             }
            }
        

        第二屏

         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'),
                    ),
                  ),
               );
             }
            }
        

        传递数据并返回
        如果要传递数据并返回,请在 SecondScreen 中添加带参数的构造函数并 在方法 Fisrt 中调用 setState 如下:

         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
            });
          }
        

        【讨论】:

          【解决方案11】:

          要摆脱黑屏,你也可以使用下面的方法和你想要的尽可能多的 pop()

          Navigator.of(context)..pop()..pop();
          

          【讨论】:

            【解决方案12】:

            检查您的Navigator.push 代码

            Navigator.of(context).pushReplacement(
                        MaterialPageRoute(builder: (context) => Nextscreen()));
            

            如果你使用.pushReplacement你不能返回,这意味着你不能使用Navigator.pop(context)

            否则,如果您使用过

            Navigator.push(context, MaterialPageRoute(builder: (context) => ListScreen(),),);
            

            请使用它来解决问题。

            Navigator.of(context, rootNavigator: true).pop(context);
            

            【讨论】:

              【解决方案13】:
              1. 导入你想去的页面。

              2. 使用Page-Ex.Appointment的类

              Navigator.push(context,new MaterialPageRoute(builder: (context)=> new Appointment() ),);
              
              3. Remove Push name from Navigator
              

              【讨论】:

                【解决方案14】:

                initialRoute 被删除时也会出现此行为,如果您使用以下命令导航到您的第一个孩子,可能会发生这种情况:

                Navigator.popAndPushNamed('...')
                

                解决方案显然很简单,只需改用pushNamed

                【讨论】:

                  【解决方案15】:

                  在导航到另一个屏幕之前使用Navigator.pop(context)

                  例子:

                  Navigator.pop(context),
                  Navigator.of(context).pushAndRemoveUntil(
                  MaterialPageRoute(uilder: (_) => GoogleMapScreenRemasterd()),
                  (Route<dynamic> route) => false),
                  

                  【讨论】:

                    【解决方案16】:

                    这对我有用,我认为这是更好的解决方案。

                    WidgetsBinding.instance.addPostFrameCallback((_) {
                                Navigator.pushReplacement(context, MaterialPageRoute(builder: (_) => Menu()));
                              }),
                    

                    【讨论】:

                      【解决方案17】:

                      我有同样的问题,比如返回相同的屏幕返回黑屏

                          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"),),
                              ) ;
                          
                            }
                          }
                      

                      然后我检查我的代码并意识到我传递了错误的类,我必须返回具有我的小部件树的类,因此如下所示将 Myapp() 替换为 Todo() 并解决我的问题

                      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"),),
                          ) ;
                      
                        }
                      }
                      

                      【讨论】:

                        【解决方案18】:

                        我想分享我在这方面的经验,因为我遇到了同样的问题。

                        基本上,来自empty screen stackpop是这个问题的主要原因。

                        在我的情况下,我在scanner_screen(通过我的main_screen上的按钮将其推送到堆栈)上进行定期操作(从相机读取一些数据),当相机找到特定文本时,我调用@987654322 @。问题是相机读取速度太快,因此我不止一次popped,这意味着从空堆栈中弹出。

                        起初我虽然弹出速度足够快,可以在我的扫描仪屏幕上调用 dispose 以停止调用不断弹出的周期性操作,但事实并非如此。这就是为什么我需要确保在从屏幕堆栈弹出之前手动停止周期性操作。

                        希望对大家有所帮助。

                        【讨论】:

                          【解决方案19】:

                          此解决方案可能有助于其他人避免黑屏。因为它对我有帮助。

                           if(Navigator.canPop(context)){
                                Navigator.of(context).pop();
                              }else{
                                SystemNavigator.pop();
                              }
                          

                          【讨论】:

                            【解决方案20】:

                            这是一个常见问题。这些只是简单的问题。当您按下新屏幕并且还有MaterialApp() 小部件时会发生这种情况。

                            【讨论】:

                              猜你喜欢
                              • 1970-01-01
                              • 2021-07-28
                              • 2019-09-19
                              • 1970-01-01
                              • 2021-07-31
                              • 2021-05-18
                              • 1970-01-01
                              • 2019-08-28
                              • 1970-01-01
                              相关资源
                              最近更新 更多