当我学习 Flutter 时,我开始学习导航。我想在屏幕之间传递数据,类似于 passing data between Activities in Android 和 passing data between View Controllers in iOS。我如何在 Flutter 中做到这一点?
相关问题:
在 Flutter 中的小部件之间传递数据的最佳方式
Flutter 在小部件之间传递数据?
Flutter/StatefulWidget之间如何传递和获取数据
Redux
框架的库。例如,flutter_flux
实现了由 Actions
、Stores
和 StoreWatchers
(pub.dartlang.org/packages/flutter_flux) 组成的单向数据流模式。提供了一个很好的框架来控制应用程序状态并传递数据
这个答案将涵盖向前传递数据和向后传递数据。与 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);
}
}
通过在构造函数中传递变量,此解决方案非常简单:
第一页:
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 中的数据,而无需传递给状态;
获得完美解决方案:
从第一个屏幕导航到其他屏幕: Navigator.pushNamed(context, "second",arguments: {"name" : "Bijendra", "rollNo": 65210}); },在构建方法的第二个屏幕上获取为:@override Widget build(BuildContext context) { final Map
最简单的方法
第一页.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);
}
}
_PasswordPageState
类中引用 usernameController
,我会收到错误:usernameController not defined
。如果我使用 widget.usernameController
,则效果很好。
上面的答案对于小型应用程序很有用,但如果你想消除不断担心小部件状态的头痛,谷歌提供了 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 包,你就可以终身受益 :)
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,
),
),
),
Flutter 中的导航器类似于 Android 中的 Intent。我们正在处理两个类 FirstScreen 和 SecondScreen。
为了在第一个屏幕到第二个屏幕之间传递数据,请执行以下操作:首先在 SecondScreen 类构造函数中添加参数
现在在 FirstScreen 类中提供参数
Navigator.push(context, MaterialPageRoute(builder: (context)=>SecondScreen(key_name:"Desired Data"));
因此,在上面的行中,“key_name”是 SecondScreen 类中给出的参数的名称。 “所需数据”是应通过密钥传递给 SecondScreen 类的数据。
这样你就完成了!!!
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);
}
这是另一种方法。
其他答案没有错。我已经尝试使用全局范围的小部件(如提供程序、第三方解决方案、导航器参数等)提到的所有方法。这种方法的不同之处在于允许链接调用并将所需的任何类型的精确数据传递给使用它的小部件。我们还可以访问完成处理程序事件,并且可以使用此技术而不受导航器对象的限制。
这是 tldr:
tldr;我们必须稍微改变一下思路。当您通过在目标小部件中使用具有默认值的最终参数导航到被调用小部件时,可以将数据传递给它。使用可选功能,您可以从“子”(目标)小部件获取数据。
完整的解释可以使用这个 SO answer.,(Gist)
我只是想在这里帮助那 1% 可能会经历我所做的事情的人 Lol
不要忘记在第一页的“Navigator.push”前面加上一个“await”,否则从第二页弹出时不会有数据返回到第一页...