如何将非字符串数据传递给 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 不应该将UserDetailsUserList 包装到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.pushNamedNavigator.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

如何通过数组将数据传递给表格视图?

如何将表单 FormSeetController 中的数据传递给 ViewController?

制作某种具有多行的行构建器并将 JSON 数据传递给其中的最佳方法是啥。扑