我想使用抽屉导航到不同的路线,但是如果我已经在路线上,我每次点击它时都不想打开路线的新实例,而是我希望在这种情况下新路线未打开。到目前为止,这是我的代码:
Widget build(BuildContext context){
return new Drawer(
child:
new ListView(
children: <Widget>[
new ListTile(
title: new Text("NewRoute"),
onTap: () {
Navigator.of(context).pop;
Navigator.of(context).pushNamed('/NewRoute');
}
)
)
)
}
我想使用条件语句来检查我们是否在某条路线上。我知道有一种方法可以检查我们目前使用Route类的isCurrent的路线
https://docs.flutter.io/flutter/widgets/Route/isCurrent.html
虽然我不确定如何实现它。
提前谢谢!
答案 0 :(得分:8)
Navigator
不会公开当前路线。
你可以做的是使用Navigator.popUntil(callback)
作为popUtil
传递给当前Route
的回调,其中包括它的名称和内容。
final newRouteName = "/NewRoute";
bool isNewRouteSameAsCurrent = false;
Navigator.popUntil(context, (route) {
if (route.settings.name == newRouteName) {
isNewRouteSameAsCurrent = true;
}
return true;
});
if (!isNewRouteSameAsCurrent) {
Navigator.pushNamed(context, newRouteName);
}
答案 1 :(得分:8)
这是Dart扩展方法的完美用例(基于RémiRousselet的回答):
extension NavigatorStateExtension on NavigatorState {
void pushNamedIfNotCurrent( String routeName, {Object arguments} ) {
if (!isCurrent(routeName)) {
pushNamed( routeName, arguments: arguments );
}
}
bool isCurrent( String routeName ) {
bool isCurrent = false;
popUntil( (route) {
if (route.settings.name == routeName) {
isCurrent = true;
}
return true;
} );
return isCurrent;
}
}
然后看起来像这样干净:
Navigator.of(context).pushNamedIfNotCurrent('/NewRoute');
答案 2 :(得分:3)
Rémi's answer确实为我提供了帮助,但是如果您像我一样是Flutter / Dart的新手,则需要一段时间才能理解。因此,这是我的版本,其中包含一些额外的检查和解释性文档:
org.apache.spark.SparkException: Job aborted due to stage failure: Task 5.0 in stage 42.0 (TID 692) had a not serializable result: org.apache.hadoop.io.IntWritable
请注意,使用/// Navigates through the application. Only replaces the top Route if it is
/// different from the new Route. Always keeps the home page as base of the
/// Navigator stack. New screens are pushed on the Navigator stack. When the
/// user switches between non-home screens, the new screen replaces the old
/// screen. In this way, the stack of screens from the drawer is never higher
/// than 2. Returning to the HomeScreen is done by just popping the current
/// Route.
void _changeRoute(BuildContext context, String newRouteName) {
// Close drawer
Navigator.pop(context);
// Check current screen status
bool currentRouteIsHome = false;
bool currentRouteIsNewRoute = false;
Navigator.popUntil(context, (currentRoute) {
// This is just a way to access currentRoute; the top route in the
// Navigator stack.
if (currentRoute.settings.name == HomeScreen.ROUTE_NAME) {
currentRouteIsHome = true;
}
if (currentRoute.settings.name == newRouteName) {
currentRouteIsNewRoute = true;
}
// Return true so popUntil() pops nothing.
return true;
});
// Switch screen
if (!currentRouteIsNewRoute) {
// Only switch screen if new route is different from current route.
if (currentRouteIsHome) {
// Navigate from home to non-home screen.
Navigator.pushNamed(context, newRouteName);
} else {
if (newRouteName == HomeScreen.ROUTE_NAME) {
// Navigate from non-home screen to home.
Navigator.pop(context);
} else {
// Navigate from non-home screen to non-home screen.
Navigator.popAndPushNamed(context, newRouteName);
}
}
}
}
和pushNamed
的此实现要求您在popAndPushNamed
参数的顶级Route
中定义MaterialApp
名称,如下所示:
routes:
答案 3 :(得分:2)
您可以只使用一个:
Get.currentRoute
使用此软件包:https://pub.dev/packages/get
您将获得当前路线。
但是您不需要它,因为与标准Flutter不同,Get可以防止用户不小心单击两次按钮(如果用户使用的是低成本设备,则该操作会在抽动之后发生)。
然后,您只需要使用:Get.to(Home());
并准备就绪,即可完成!
当前,由于这个原因,Getx实际上对于Flutter的项目是必不可少的。 我查看了所有问题,它们很酷,但是它们通常涉及使用popUntil来访问路由,并且当其他开发人员读取您的代码时,这似乎像是骇客。 使用GetX,您将不会遇到双击问题,因为只有使用Get.to(Page(),preventDuplicates:false)明确禁用它,它才会导航到同一页面的另一个页面。 记住这是个例外,在您的情况下,您可以简单地使用: Get.to(Page());并导航至下一页,而不会出现重复路线的风险,因为防止这种情况已经成为标准。
获取当前路线似乎也涉及很多样板,使用Get可以获取当前路线的名称(即使您没有命名路线也可以为您提供名称),使用简单的Get.currenteRoute
。
嗯,回答这个问题有点晚了,但是我希望您和其他阅读此内容的用户喜欢
答案 4 :(得分:0)
使用以下代码检查路线是否最重要......
Route route = MaterialPageRoute(builder: (context) => WidgetName());
if(route.isCurrent){
}
答案 5 :(得分:0)
我正在使用此代码。
*Route route = MaterialPageRoute(builder: (context) => Myinternet());
print(route.isCurrent);
if(route.isCurrent){
}*
输出:
显示总是 false 当前页面找不到
答案 6 :(得分:0)
这应该给您确切的路线名称
import 'package:path/path.dart';
ModalRoute.of(context).settings.name
为避免null异常,请执行此操作
var route = ModalRoute.of(context);
if(route!=null){
print(route.settings.name);
}
答案 7 :(得分:0)
这是我的解决方法。
void redirect(screen){
Navigator.popUntil(context, (route) {
if ( route.settings.name != screen) {
Navigator.pushNamed(context, screen);
}
return true;
});
}
答案 8 :(得分:0)
ModalRoute.of(context).settings.name
是解决此问题的很好的API,但是不能在initState()中使用
答案 9 :(得分:0)
对我来说,我使用的是最懒惰的最简单的方法,因为这里没有答案可以帮助我实现主路线,我只是使用抽屉类,并将当前路线的名称传递给抽屉构造函数,如下所示:
class MyDrawer extends StatelessWidget {
final String currentRoute;
MyDrawer(this.currentRoute);
@override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
children: <Widget>[
InkWell(
child: Text('secondRoute'),
onTap: () {
if (currentRoute != 'secondRoute')
Navigator.push(context,
MaterialPageRoute(builder: (context) => secondRoute()));
}),
InkWell(
child: Text('thirdRoute'),
onTap: () {
if (currentRoute != 'thirdRoute')
Navigator.push(context,
MaterialPageRoute(builder: (context) => thirdRoute()));
}),
在我调用MyDrawer类的路线中,我传递了当前路线的名称
drawer: MyDrawer('secondRoute'),
答案 10 :(得分:0)
这是我的解决方案。基于RémiRousselet解决方案。 唯一的区别是,可以防止剩余“最后”路线的弹出。
bool routeFound = false;
String routeName = "/myRoute";
//remove all the routes and stops if find the routeName or if is the last one
Navigator.popUntil(context, (route) {
if (route.settings.name == routeName) {
expenseRouteFound = true;
}
//print("route " + routeName + " founded in stack: " + routeFound.toString());
//print("last remaining route into the stack: " + route.isFirst.toString());
return routeFound || route.isFirst;
});
//print("route " + routeName + " founded in stack: " + routeFound.toString());
if (!routeFound) {
//print("time to push the route: " + routeName + "!");
Navigator.of(context).pushNamedAndRemoveUntil(routeName, (_)=>false);
}
答案 11 :(得分:0)
基于 Rémi Rousselet 的回答。
String? currentPath;
navigatorKey.currentState?.popUntil((route) {
currentPath = route.settings.name;
return true;
});