Flutter Navigator.pop(context) 返回黑屏



我的 Flutter 项目结构是这样的

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) 返回 false 但是硬件后退按钮工作绝对正常,那么我该如何修复它?

主飞镖

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)

我正在使用维吉尔,但我认为这不是问题所在。

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

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

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

因此,黑屏。

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

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

之后不再有黑屏。

只需添加可选的参数rootNavigator: true: 样本:

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

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

我使用以下代码解决它:

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

解决方法SystemNavigator.pop();从此链接引用

我也遇到了这个问题,在尝试了所有这些以前的答案后,我仍然得到黑屏。我对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())

我有一个非常相似的问题,我的解决方案是将 BuildContext 上下文从创建的 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的后退按钮一样。 =)

我不知道这是否是一种好的做法。如果有人知道"更正确"的方法,请随时回答。

检查您的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);

根据这个答案,我想出了一个办法。

您应该将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 中添加一个带有参数的构造函数,然后 调用 setState 在方法 Fisrtlike 中像这样:

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

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

具有技术思维的材料应用程序包含应用程序标题和主屏幕小部件

这是我的实现

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

也许在详细屏幕中,您将 MaterialApp 用作主要小部件,您只需删除 MaterialApp 并直接返回脚手架,也许您的问题会解决这个问题对我来说是工作。

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

而不是

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

要摆脱黑屏,您还可以使用以下方法和任意数量的 pop()

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

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

基本上,从空屏幕堆栈pop是此问题的主要原因。

就我而言,我正在对scanner_screen(由main_screen上的按钮推到堆栈)进行定期操作(从相机读取一些数据),当相机找到特定文本时,我调用pop。问题是相机读取速度太快,因此我不止一次pop踏板,这意味着从空堆栈中弹出。

起初,我认为弹出足够快,可以在我的scanner_screen上调用 dispose 以停止调用不断弹出的定期操作,但事实并非如此。这就是为什么我需要确保在从屏幕堆栈弹出之前手动停止定期操作的原因。

我希望这可能会对某人有所帮助。

当我使用 Navigator.pop() 时,我遇到了类似的问题,它显示黑屏 我将"maybePop()"方法与"then"方法一起使用,并测试了如果为假的值,那么我将路由推送到我的主屏幕。喜欢这个:

Navigator.of(context).maybePop(context).then((value) {
if (value == false) {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => Home(),
));
}
});

我已经尝试了所有答案,但只有这段代码解决了空白屏幕问题:

if (Navigator.canPop(context)) {
Navigator.of(context, rootNavigator: true).pop(context);
}

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

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

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

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

嗯,在我的代码的第一个版本中,Huy Nguyen的回答真的帮助了我。更改一些基本代码并执行一些状态管理后,修复停止工作。

因为这是我的登录屏幕,我不需要返回此页面,所以我之前删除了所有路由。所以我的解决方法基本上是检查我是否可以弹出,如果不是手动推送到路由。

if (Navigator.canPop(context)) {
Navigator.of(context, rootNavigator: true).pop(context);
} else {
Navigator.of(context, rootNavigator: true)
.pushNamedAndRemoveUntil("/", (Route<dynamic> route) => false);
}

请注意,您可能无法在此处将数据返回到主屏幕。在这种情况下,我正在管理状态,正如这里指出的那样。我希望这对某人有所帮助。

  1. 导入您要去的页面。

  2. 使用该Page-Ex.Appointment的类

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

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

Navigator.popAndPushNamed('...')

解决方案显然很简单,只需使用pushNamed即可。

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

例:

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

对我来说这项工作,我认为这是更好的解决方案。

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

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

使用Navigator.pushNamed而不是Navigator.pushReplacementNamed

就我而言,我正在通过Navigator.pushReplacementNamed(context, '/profile');导航 但是当我像这样更改导航时:Navigator.pushNamed(context, '/profile');导航返回是否正常工作

尝试更改导航器>>>

Navigator.push(context,MaterialPageRoute(builder: (context) {
return detailspage();}));

或者您也可以尝试创建一个类,然后

class MyNav {
static navigateTo({required BuildContext ctx, required String routeName}) {
Navigator.pushNamed(ctx, routeName);
}
}

然后尝试使用路由

MyNav.navigateTo(ctx: context, routeName: detailspage.routeName);

还要在 main.dart 文件中添加 routes:{ } 以使此方法正常工作。

让我知道它是否有效。

相关内容

最新更新