如何将非字符串数据传递给 Flutter 中的命名路由?
Posted
技术标签:
【中文标题】如何将非字符串数据传递给 Flutter 中的命名路由?【英文标题】:How do I pass non-string data to a named route in Flutter? 【发布时间】:2018-05-05 07:38:59 【问题描述】:我有很多屏幕,我使用的是Navigator
。我想使用“命名路线”,但我还需要将非字符串(例如图像)传递给我的下一条路线。
我不能使用pushNamed()
,因为我不能将非字符串数据传递给它。
如何使用命名路由+发送非字符串数据?
【问题讨论】:
flutter.dev/docs/cookbook/navigation/navigate-with-arguments 这对我有帮助 【参考方案1】:编辑:
现在可以将复杂的参数传递给Navigator.pushNamed
:
String id;
Navigator.pushNamed(context, '/users', arguments: id);
然后可以在onGenerateRoute
中使用这些参数自定义路由构建:
MaterialApp(
title: 'Flutter Hooks Gallery',
onGenerateRoute: (settings)
final arguments = settings.arguments;
switch (settings.name)
case '/users':
if (arguments is String)
// the details page for one specific user
return UserDetails(arguments);
else
// a route showing the list of all users
return UserList();
default:
return null;
,
);
【讨论】:
当路由是 /myRoute/$myID 时,路径拆分在列表中有 3 个项目,第一个是空字符串“”。也许我们必须忽略 path[0] 而使用 path[1] 和 path[2]? 以上答案还有效吗?我看不到通过RouteSettings
提供的arguments
属性...
它是最近添加的。您可能需要切换频道。
这里是此功能的拉取请求:github.com/flutter/flutter/pull/27058
不应该将UserDetails
和UserList
包装到MaterialPageRoute
中吗?【参考方案2】:
您可以使用应用程序的参数routes
直接传递参数。
像这样:
routes:
HomePage.route: (_) => HomePage(),
DetailsPage.route: (context) =>
DetailsPage(ModalRoute.of(context).settings.arguments),
,
在这种情况下,完整的示例将如下所示:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return MaterialApp(
title: 'Flutter Demo',
initialRoute: HomePage.route,
routes:
HomePage.route: (_) => HomePage(),
DetailsPage.route: (context) =>
DetailsPage(ModalRoute.of(context).settings.arguments),
,
);
class HomePage extends StatelessWidget
static const String route = '/';
@override
Widget build(BuildContext context)
return Scaffold(
body: Container(),
floatingActionButton: FloatingActionButton(
onPressed: ()
Navigator.pushNamed(context, '/details',
arguments: ScreenArguments(
'My Details',
'Some Message',
));
,
),
);
class DetailsPage extends StatelessWidget
static const String route = '/details';
final ScreenArguments arguments;
DetailsPage(this.arguments);
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(
title: Text(arguments.title),
),
body: Center(
child: Text(arguments.message),
),
);
class ScreenArguments
final String title;
final String message;
ScreenArguments(this.title, this.message);
【讨论】:
我认为“initialRoute”已被弃用。【参考方案3】:使用地图
在推送参数时,您可以以映射形式推送它,并且在提取它们时也可以这样做。
例如
推送时
Navigator.of(context).pushNamed(
'second',
arguments:
'title':'This is a String',
or
'Fx': This could be any widget or Function
提取时目标页面中的参数
final routes=ModalRoute.of(context).settings.arguments as Map<String,String>;
return Scaffold(
appBar: AppBar(
title: Text(routes['title']),
),
body: Container(
child: Center(
child: RaisedButton(
child: Text("Back"),
onPressed: ()=>Navigator.of(context).pop(),
),
),
),
);
and choose your map accordingly accordingly
【讨论】:
简单非生成路由的最佳示例:)【参考方案4】:更新日期:2021 年 4 月 3 日
这个答案是旧的,从那时起 Flutter 导航已经有了很大的发展。这可能不是处理当前版本导航的最佳方式,请考虑其他答案。出于历史目的,我将把它留在这里。
使用onGenerateRoute
可以很容易地通过Navigator.pushNamed
或Navigator.pushReplacementNamed
传递复杂的路由转换参数
展示这个概念的最小设置是
main.dart
import 'package:flutter/material.dart';
import 'package:navigator/routes.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget
@override
Widget build(BuildContext context)
return MaterialApp(
title: 'Flutter Navigation Demo',
theme: ThemeData(
primarySwatch: Colors.teal,
),
onGenerateRoute: (RouteSettings settings)
return MaterialPageRoute(
builder: (BuildContext context) => makeRoute(
context: context,
routeName: settings.name,
arguments: settings.arguments,
),
maintainState: true,
fullscreenDialog: false,
);
,
);
routes.dart
在_buildRoute
方法中,我们检查路由名称并将参数转换为所需的类型。
缺点是如果所需参数不是简单类型,则必须事先定义类型。
import 'package:flutter/material.dart';
import 'package:navigator/list.dart';
import 'package:navigator/details.dart';
Widget makeRoute(
@required BuildContext context,
@required String routeName,
Object arguments)
final Widget child =
_buildRoute(context: context, routeName: routeName, arguments: arguments);
return child;
Widget _buildRoute(
@required BuildContext context,
@required String routeName,
Object arguments,
)
switch (routeName)
case '/':
return ArticleList();
case '/ArticleView':
Article article = arguments as Article;
return ArticleView(article: article);
default:
throw 'Route $routeName is not defined';
观看次数
list.dart
使用定义的类型构造路由参数,在我们的例子中是Article
。
import 'package:flutter/material.dart';
import 'package:navigator/details.dart' show Article;
class ArticleList extends StatefulWidget
@override
_ArticleListState createState() => _ArticleListState();
class _ArticleListState extends State<ArticleList>
List<Article> articles = [
Article(
id: 1,
title: 'Article 1',
author_name: 'Nilotpal',
summary: 'Article 1 summary'),
Article(
id: 2,
title: 'Article 2',
author_name: 'Mike',
summary: 'Article 2 summary'),
];
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(
title: Text('Articles'),
),
body: Center(
child: Column(
children: <Widget>[
ListTile(
title: Text('$articles[0].title'),
subtitle: Text('by $articles[0].author_name'),
onTap: ()
Navigator.of(context)
.pushNamed('/ArticleView', arguments: articles[0]);
,
),
ListTile(
title: Text('$articles[1].title'),
subtitle: Text('by $articles[1].author_name'),
onTap: ()
Navigator.of(context)
.pushNamed('/ArticleView', arguments: articles[1]);
,
),
],
),
),
);
details.dart
定义参数的类型
import 'package:flutter/material.dart';
class Article
final int id;
final String author_name;
final String title;
final String summary;
Article(
@required this.id,
@required this.author_name,
@required this.title,
@required this.summary);
class ArticleView extends StatelessWidget
final Article _article;
ArticleView(@required Article article) : _article = article;
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(
title: Text('$_article.title'),
),
body: SafeArea(
top: true,
child: Center(
child: Column(
children: <Widget>[
Text('$_article.author_name'),
Text('$_article.summary'),
],
),
),
),
);
【讨论】:
对最小的设置赞不绝口。【参考方案5】:Flutter Cookbook 展示了如何导航到新页面并向其传递非字符串数据。
Passing data to next page
我从Navigator.pushedNamed()
开始,因为它很简单,而且我没有任何数据要传递。当我的需求发生变化并想传递数据时,我切换到Navigator.push()
。
例子:
var nextPageData = foo:'bar';
Navigator.push(
context,
MaterialPageRoute(builder: (context) =>
MyNextPage(myData: nextPageData))
);
【讨论】:
如何将非字符串数据传递给 Flutter 中的命名路由?【参考方案6】:我正在用相机拍摄图像,然后将它们传递到一个确认页面,如下所示:
ImagePicker.pickImage(source: source).then((File file)
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MediaCaptured(file: file),
));
);
您可以轻松地对任何类型的文件或非字符串数据执行相同操作。
var foo = "non-string data";
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MediaCaptured(foo: foo),
));
通过类名调用路由中的下一页,如上所述。
只要确保你的新页面在它的构造函数中接受这个。
// Stateful Widget
class MediaCaptured extends StatefulWidget
MediaCaptured( Key key, @required this.foo,) : super(key: key);
final var foo;
// StatelessWidget
class MediaCaptured extends StatelessWidget
MediaCaptured(this.foo);
var foo;
【讨论】:
【参考方案7】:针对这个问题的结果,我开发了包
链接:https://pub.dartlang.org/packages/navigate
这提供了您的期望并且易于使用
Navigate.navigate(context,
"home",
transactionType:TransactionType.fromLeft , // optional
replaceRoute: ReplaceRoute.thisOne, //optional
arg: "transactionType":TransactionType.fromLeft,"replaceRoute":ReplaceRoute.thisOne //optional
);
【讨论】:
【参考方案8】:来自第一个 StateFul 类:
Navigator.of(context).pushNamed('/pending_order',arguments: "staff" : staffObj);
到第二个 StateFul 类:
class PendingOrders extends StatefulWidget
@override
_PendingOrdersState createState() => _PendingOrdersState();
class _PendingOrdersState extends State<PendingOrders>
StaffModel staffModelObj;
@override
Widget build(BuildContext context)
final routes =
ModalRoute.of(context).settings.arguments as Map<String, dynamic>;
if (routes != null)
staffModelObj = routes["staff"];
return Scaffold(...);
【讨论】:
【参考方案9】:We can pass any type of arguments when declaring routes as constructor arguments as below,
For example to send a list of Strings,
List<String> titles = [];
void main() => runApp(
new MaterialApp(
home: new FirstPage(),
routes: <String, WidgetBuilder>
"/SecondPage": (BuildContext context) => new SecondPage(titles),
,
),
);
class FirstPage extends StatelessWidget
@override
Widget build(BuildContext context)
return new Container(
child: new RaisedButton(onPressed: ()
Navigator.of(context).pushNamed('/SecondPage');
),
);
class SecondPage extends StatelessWidget
final List<String> titles;
SecondPage(this.titles);
@override
Widget build(BuildContext context)
return new ListView.builder(
itemBuilder: (context, index)
return new ListTile(
title: new Text(titles[index]),
);
,
);
【讨论】:
以上是关于如何将非字符串数据传递给 Flutter 中的命名路由?的主要内容,如果未能解决你的问题,请参考以下文章
在 Flutter 中,如何将数据传递给 Stateless Widget?
Flutter(Web)如何监听javascript事件或将javascript数据传递给flutter?
Flutter 将搜索数据传递给 SearchDelegate