ChatGPT解决这个技术问题 Extra ChatGPT

在 Flutter 中的屏幕之间传递数据

当我学习 Flutter 时,我开始学习导航。我想在屏幕之间传递数据,类似于 passing data between Activities in Androidpassing data between View Controllers in iOS。我如何在 Flutter 中做到这一点?

相关问题:

在 Flutter 中的小部件之间传递数据的最佳方式

Flutter 在小部件之间传递数据?

Flutter/StatefulWidget之间如何传递和获取数据

您可以使用在 Flutter 中实现 Redux 框架的库。例如,flutter_flux 实现了由 ActionsStoresStoreWatchers (pub.dartlang.org/packages/flutter_flux) 组成的单向数据流模式。提供了一个很好的框架来控制应用程序状态并传递数据
最后一个链接实际上是 stackoverflow.com/questions/46057353/… 的副本
第二个链接实际上也是如此
TODO 为提供程序包添加答案
遗憾的是,在 Navigator.push() 之后使用 StreamProvider 和 Provider.of() 时,没有一个答案对实时流有帮助,它不再是实时的。

S
Suragch

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

将数据转发到下一个屏幕

https://i.stack.imgur.com/KcrwL.png

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

使 SecondScreen 构造函数采用您要发送给它的数据类型的参数。在此特定示例中,数据被定义为字符串值,并在此处使用 this.text 进行设置。类 SecondScreen 扩展 StatelessWidget { 最终字符串文本; SecondScreen({Key key, @required this.text}) : super(key: key); ...然后使用 FirstScreen 小部件中的导航器将路由推送到 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),
        ),
      ),
    );
  }
}

将数据传回前一个屏幕

https://i.stack.imgur.com/cspnX.png

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

在 FirstScreen 中,使用 Navigator 以异步方法推送(启动)SecondScreen 并等待它在完成时返回的结果。最终结果 = await Navigator.push(context, MaterialPageRoute(builder: (context) => SecondScreen(), ));在 SecondScreen 中,包括您想要在弹出导航器时作为参数传回的数据。 Navigator.pop(context, '你好');然后在 FirstScreen 中等待将完成,您可以使用结果。 setState(() { 文本 = 结果; });

以下是 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);
  }
}

如果我的第二个页面是有状态的小部件,我该怎么做?我不能在构造函数中调用 setState ...
@MrLalatg 如果您使用有状态小部件,请使用“widget.$variable_name”获取数据。字符串 tempText = widget.text
可以像这样发送任意大量数据吗?我知道在 Android 中,应该尽量减少通过“活动”传递数据。
如果用户按下移动设备的后退按钮而不是按下“RaisedButton”按钮,那么我们如何将 textFieldController.text 传递并发送回第一个屏幕?请建议。
@coditori,我不必实现该特定用例,但请查看 go_router 包。这就是我现在开始使用的导航。
C
CopsOnRoad

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

第一页:

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

您不需要将数据传递给此处的状态 return SecondPageState(this.something); 您可以直接以 widget.something 的形式访问 SecondPageState 中的数据,而无需传递给状态;
S
Suragch

获得完美解决方案:

从第一个屏幕导航到其他屏幕: Navigator.pushNamed(context, "second",arguments: {"name" : "Bijendra", "rollNo": 65210}); },在构建方法的第二个屏幕上获取为:@override Widget build(BuildContext context) { final MaprcvdData = 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: [ Text("Second"), ],),),); }


嗨,无论如何,在加载第二个小部件后重置参数。谢谢
佚名

最简单的方法

第一页.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);
}
}

widget.usernameController 为我工作,但不仅仅是 usernameController,正如@Suragch 所说,我不知道这是因为不同的方法还是更新的颤振版本
如果我在 _PasswordPageState 类中引用 usernameController,我会收到错误:usernameController not defined。如果我使用 widget.usernameController,则效果很好。
s
serg

上面的答案对于小型应用程序很有用,但如果你想消除不断担心小部件状态的头痛,谷歌提供了 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 包,你就可以终身受益 :)


没有多少人意识到这个回复的重要性。感谢您的视频链接:)
V
Varsha

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

它产生一个错误未处理的异常:NoSuchMethodError:getter 'focusScopeNode'被调用为空。
我在异步功能
H
Hasan A Yousef

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

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

现在在 FirstScreen 类中提供参数

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

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

这样你就完成了!!!


A
Anil Kumar

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

J
Jewel Rana

如果你使用 get 包,那么试试这个。 passing data with get package

检查获取包 package link


T
Tommie C.

这是另一种方法。

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

这是 tldr:

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

完整的解释可以使用这个 SO answer.(Gist)


D
Dharman

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

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


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅