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

Sur*_*gch 26 dart flutter flutter-navigation

当我正在学习Flutter时,我来到导航.我想屏幕之间的数据传递类似于Android中传递活动之间的数据iOS中查看控制器之间传递数据.我如何在Flutter中做到这一点?

相关问题:

我正在创建这个规范问答,因为我找不到Flutter的另一个.我的答案如下.

Sur*_*gch 58

这个答案将涵盖向前传递数据和传回数据.与Android Activities和iOS ViewControllers不同,Flutter中的不同屏幕只是小部件.在它们之间导航涉及创建称为路由的东西,并使用Navigator推送和弹出堆栈上下的路由.

将数据传递到下一个屏幕

在此输入图像描述

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

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

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

    Navigator.push(
        context,
        MaterialPageRoute(
          builder: (context) => SecondScreen(text: 'Hello',),
        ));
    
    Run Code Online (Sandbox Code Playgroud)

完整的代码在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),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

将数据传回上一屏幕

在此输入图像描述

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

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

    final result = await Navigator.push(
        context,
        MaterialPageRoute(
          builder: (context) => SecondScreen(),
        ));
    
    Run Code Online (Sandbox Code Playgroud)
  2. SecondScreen,弹出时,包括要作为参数传回的数据Navigator.

    Navigator.pop(context, 'Hello');
    
    Run Code Online (Sandbox Code Playgroud)
  3. 然后在FirstScreenawait会结束,你可以使用的结果.

    setState(() {
      text = result;
    });
    
    Run Code Online (Sandbox Code Playgroud)

以下是完整的代码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);
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果我的第二页是有状态小部件,我该怎么做?我不能在构造函数中调用 setState ...... (5认同)
  • 如果您使用的是有状态小部件,@MrLalatg 使用“widget.$variable_name”来获取数据。字符串 tempText = widget.text (5认同)
  • @user3245268,我不知道数据量有任何限制。不过,我假设,如果数据量非常大,那么您只需从第二个屏幕查询数据库或其他内容,而不是从第一个屏幕传递它。 (2认同)
  • 如果用户按下移动设备的后退按钮而不是按“RaishedButton”按钮,那么我们如何传递 textFieldController.text 并将其发送回第一个屏幕?请建议。 (2认同)

小智 33

获得完美解决方案:

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

    Navigator.pushNamed(context, "second",arguments: {"name" : 
      "Bijendra", "rollNo": 65210});
    },
    
    Run Code Online (Sandbox Code Playgroud)
  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"),
        ],),),);
    
    }
    
    Run Code Online (Sandbox Code Playgroud)


ser*_*erg 8

上面的答案对于小型应用程序很有用,但是如果您想消除持续担心小部件状态的麻烦,Google 提供了 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 包,您就可以终身受益了 :)

  • 没有多少人意识到这个回复有多么重要。感谢您提供视频链接:) (2认同)

小智 7

最简单的方法

FirstPage.dart

 Navigator.push(
          context,
          MaterialPageRoute(
              builder: (context) => PasswordRoute(usernameController)));
Run Code Online (Sandbox Code Playgroud)

// usernameController是字符串值,如果要传递多个值,请添加所有

SecondPage.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);
}
}
Run Code Online (Sandbox Code Playgroud)


Mah*_*ber 6

This solution is very easy by passing variables in constructor:

first page:

Navigator.of(context).push(MaterialPageRoute(builder:(context)=>SecondPage('something')));
Run Code Online (Sandbox Code Playgroud)

second page:

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),
   ),
   ...
  }
Run Code Online (Sandbox Code Playgroud)

  • 你不需要在这里传递数据到 state ```return SecondPageState(this.something);``` 你可以直接以 ```widget.something``` 的形式访问 SecondPageState 中的数据,而不需要传递到 state; (8认同)

小智 5

第一屏幕: //发送数据到第二屏幕

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

                          }));
Run Code Online (Sandbox Code Playgroud)

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

 final String username;
  WelcomeUser(this.username);
Run Code Online (Sandbox Code Playgroud)

//使用数据来显示

body: Container(
    child: Center(
      child: Text("Welcome "+widget.username,
      textAlign: TextAlign.center,
      ),
    ),
  ),
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

22414 次

最近记录:

5 年,11 月 前