88

当我学习 Flutter 时,我开始学习导航。我想在屏幕之间传递数据,类似于在 Android 中的活动之间传递数据以及在 iOS 中的视图控制器之间传递数据。我如何在 Flutter 中做到这一点?

相关问题:

4

11 回答 11

205

这个答案将涵盖向前传递数据和向后传递数据。与 Android 活动和 iOS 视图控制器不同,Flutter 中的不同屏幕只是小部件。在它们之间导航涉及创建称为路由的东西,并使用 将Navigator路由推入和弹出堆栈。

将数据转发到下一个屏幕

在此处输入图像描述

要将数据发送到下一个屏幕,请执行以下操作:

  1. 使SecondScreen构造函数接受您要发送给它的数据类型的参数。在此特定示例中,数据被定义为一个String值,并在此处设置为this.text

    class SecondScreen extends StatelessWidget {
      final String text;
      SecondScreen({Key key, @required this.text}) : super(key: key);
    
      ...
    
  2. 然后使用小部件NavigatorFirstScreen的 将路由推送到SecondScreen小部件。您将要发送的数据作为参数放入其构造函数中。

    Navigator.push(
        context,
        MaterialPageRoute(
          builder: (context) => SecondScreen(text: 'Hello',),
        ));
    

完整的代码在main.dart这里:

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    title: 'Flutter',
    home: FirstScreen(),
  ));
}

class FirstScreen extends StatefulWidget {
  @override
  _FirstScreenState createState() {
    return _FirstScreenState();
  }
}

class _FirstScreenState extends State<FirstScreen> {

  // this allows us to access the TextField text
  TextEditingController textFieldController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('First screen')),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [

          Padding(
            padding: const EdgeInsets.all(32.0),
            child: TextField(
              controller: textFieldController,
              style: TextStyle(
                fontSize: 24,
                color: Colors.black,
              ),
            ),
          ),

          RaisedButton(
            child: Text(
              'Go to second screen',
              style: TextStyle(fontSize: 24),
            ),
            onPressed: () {
              _sendDataToSecondScreen(context);
            },
          )

        ],
      ),
    );
  }

  // get the text in the TextField and start the Second Screen
  void _sendDataToSecondScreen(BuildContext context) {
    String textToSend = textFieldController.text;
    Navigator.push(
        context,
        MaterialPageRoute(
          builder: (context) => SecondScreen(text: textToSend,),
        ));
  }
}

class SecondScreen extends StatelessWidget {
  final String text;

  // receive data from the FirstScreen as a parameter
  SecondScreen({Key key, @required this.text}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Second screen')),
      body: Center(
        child: Text(
          text,
          style: TextStyle(fontSize: 24),
        ),
      ),
    );
  }
}

将数据传回前一个屏幕

在此处输入图像描述

传回数据时,您需要执行以下操作:

  1. 在 中FirstScreen,使用Navigator推入(启动)SecondScreen方法async并等待它完成时返回的结果。

    final result = await Navigator.push(
        context,
        MaterialPageRoute(
          builder: (context) => SecondScreen(),
        ));
    
  2. 在 中SecondScreen,包含您想要在弹出时作为参数传回的数据Navigator

    Navigator.pop(context, 'Hello');
    
  3. 然后在FirstScreenawait完成,您可以使用结果。

    setState(() {
      text = result;
    });
    

这是main.dart供您参考的完整代码。

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    title: 'Flutter',
    home: FirstScreen(),
  ));
}

class FirstScreen extends StatefulWidget {
  @override
  _FirstScreenState createState() {
    return _FirstScreenState();
  }
}

class _FirstScreenState extends State<FirstScreen> {

  String text = 'Text';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('First screen')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [

            Padding(
              padding: const EdgeInsets.all(32.0),
              child: Text(
                text,
                style: TextStyle(fontSize: 24),
              ),
            ),

            RaisedButton(
              child: Text(
                'Go to second screen',
                style: TextStyle(fontSize: 24),
              ),
              onPressed: () {
                _awaitReturnValueFromSecondScreen(context);
              },
            )

          ],
        ),
      ),
    );
  }

  void _awaitReturnValueFromSecondScreen(BuildContext context) async {

    // start the SecondScreen and wait for it to finish with a result
    final result = await Navigator.push(
        context,
        MaterialPageRoute(
          builder: (context) => SecondScreen(),
        ));

    // after the SecondScreen result comes back update the Text widget with it
    setState(() {
      text = result;
    });
  }
}

class SecondScreen extends StatefulWidget {
  @override
  _SecondScreenState createState() {
    return _SecondScreenState();
  }
}

class _SecondScreenState extends State<SecondScreen> {
  // this allows us to access the TextField text
  TextEditingController textFieldController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Second screen')),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [

          Padding(
            padding: const EdgeInsets.all(32.0),
            child: TextField(
              controller: textFieldController,
              style: TextStyle(
                fontSize: 24,
                color: Colors.black,
              ),
            ),
          ),

          RaisedButton(
            child: Text(
              'Send text back',
              style: TextStyle(fontSize: 24),
            ),
            onPressed: () {
              _sendDataBack(context);
            },
          )

        ],
      ),
    );
  }

  // get the text in the TextField and send it back to the FirstScreen
  void _sendDataBack(BuildContext context) {
    String textToSendBack = textFieldController.text;
    Navigator.pop(context, textToSendBack);
  }
}
于 2018-12-20T01:21:07.607 回答
35

获得完美解决方案:

  1. 从第一个屏幕导航到其他屏幕:

    Navigator.pushNamed(context, "second",arguments: {"name" : 
      "Bijendra", "rollNo": 65210});
    },
    
  2. 在构建方法的第二个屏幕上获取为:

    @override
    Widget build(BuildContext context) {
        final  Map<String, Object>rcvdData = ModalRoute.of(context).settings.arguments;
        print("rcvd fdata ${rcvdData['name']}");
        print("rcvd fdata ${rcvdData}");
    
        return Scaffold(appBar: AppBar(title: Text("Second")),
          body: Container(child: Column(children: <Widget>[
          Text("Second"),
        ],),),);
    
    }
    
于 2020-02-09T13:51:47.320 回答
33

通过在构造函数中传递变量,此解决方案非常简单:

第一页:

Navigator.of(context).push(MaterialPageRoute(builder:(context)=>SecondPage('something')));

第二页:

class SecondPage extends StatefulWidget {
  String something;
  SecondPage(this.something);
  @override
  State<StatefulWidget> createState() {
    return SecondPageState(this.something);
  }
}
class SecondPageState extends State<SecondPage> {
  String something;
  SecondPageState(this.something);
  @override
  Widget build(BuildContext context) {
   return Scaffold(
    appBar: AppBar(
    //now you have passing variable
    title: Text(something),
   ),
   ...
  }
于 2019-06-24T22:19:46.893 回答
28

最简单的方法

第一页.dart

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

//usernameController是String值,如果要传多个值全部加

第二页.dart

class PasswordRoute extends StatefulWidget {
  final String usernameController;//if you have multiple values add here
PasswordRoute(this.usernameController, {Key key}): super(key: key);//add also..example this.abc,this...

  @override
  State<StatefulWidget> createState() => _PasswordPageState();
}

class _PasswordPageState extends State<PasswordRoute> {
 @override
  Widget build(BuildContext context) {
...child: Text(widget.usernameController);
}
}
于 2019-03-06T06:11:59.007 回答
12

上面的答案对于小型应用程序很有用,但如果你想消除不断担心小部件状态的头痛,谷歌提供了 Provider 包。 https://pub.dev/packages/provider

看看那个,或观看 Andrea Bizzotto 的这些视频: https ://www.youtube.com/watch?v=MkFjtCov62g // 提供者:基本指南 https://www.youtube.com/watch?v =O71rYKcxUgA&t=258s // 提供者:简介

学习如何使用 Provider 包,你就可以终身受益 :)

于 2019-12-25T13:45:08.680 回答
4

First Screen : //发送数据到第二屏

 Navigator.push(context, MaterialPageRoute(builder: (context) {
                          return WelcomeUser(usernameController.text);

                          }));

第二屏: //从第一屏获取数据

 final String username;
  WelcomeUser(this.username);

//使用数据显示

body: Container(
    child: Center(
      child: Text("Welcome "+widget.username,
      textAlign: TextAlign.center,
      ),
    ),
  ),
于 2019-12-25T07:48:47.823 回答
3

Flutter 中的导航器类似于 Android 中的 Intent。我们正在处理两个类 FirstScreen 和 SecondScreen。

为了在第一个屏幕到第二个屏幕之间传递数据,请执行以下操作:首先在 SecondScreen 类构造函数中添加参数

现在在 FirstScreen 类中提供参数

Navigator.push(context, MaterialPageRoute(builder: (context)=>SecondScreen(key_name:"Desired Data"));

因此,在上面的行中,“key_name”是 SecondScreen 类中给出的参数的名称。“所需数据”是应通过密钥传递给 SecondScreen 类的数据。

这样你就完成了!!!

于 2020-05-08T17:56:23.590 回答
0

如果你使用 get 包,那么试试这个。使用 get 包传递数据

检查获取包包链接

于 2020-11-19T06:47:56.060 回答
0

我只是想在这里帮助那 1% 可能会经历我所做的事情的人 Lol

不要忘记在第一页的“Navigator.push”前面加上一个“await”,否则从第二页弹出时不会有数据返回到第一页...

于 2021-11-12T19:58:21.583 回答
0

这是另一种方法。

其他答案没有错。我已经尝试使用全局范围的小部件(如提供程序、第三方解决方案、导航器参数等)提到的所有方法。这种方法的不同之处在于允许链接调用并将所需的任何类型的精确数据传递给使用它的小部件。我们还可以访问完成处理程序事件,并且可以使用此技术而不受导航器对象的限制。

这是 tldr:

tldr; 我们必须稍微改变一下思路。当您通过在目标小部件中使用具有默认值的最终参数导航到被调用小部件时,可以将数据传递给它。使用可选功能,您可以从“子”(目标)小部件获取数据。

使用此SO 答案可以找到完整的解释。, (要点)

于 2021-09-02T05:15:07.470 回答
0

1)从您要推送的位置:

onPressed: () async {
                        await Navigator.pushNamed(context, '/edit',
                            arguments: userData);
                        setState(() {
                          userData = userData;
                        });}

2)从你想弹出的地方:

    void updateData() async{
    WorldTime instance = locations;
    await instance.getData();
    Navigator.pop(context, userData);
  }
于 2020-04-17T08:42:23.353 回答