如何在颤动的另一个有状态小部件中访问在一个有状态小部件中创建的对象

Posted

技术标签:

【中文标题】如何在颤动的另一个有状态小部件中访问在一个有状态小部件中创建的对象【英文标题】:how to access an object created in one stateful widget in another stateful widget in flutter 【发布时间】:2018-03-14 13:02:05 【问题描述】:

我被困在我的项目中,我在颤振中创建了两个有状态的小部件作为两个不同的 dart 文件。现在,我必须在第二个小部件中访问在第一个小部件中创建的对象的实例,但我不太确定在创建小部件时如何在颤振中做到这一点。

我想到的一种可能的解决方案是在一个 dart 文件中声明两个小部件,而不是在两个布局中声明两个 dart 文件,但我很好奇我们是否可以通过在两个单独的 dart 文件中声明来做到这一点。

我发布这些文件只是为了重现问题。

main.dart

 import 'package:flutter/material.dart';
 import 'package:untitled2/models.dart';
 import 'package:untitled2/secondwidget.dart';

void main() 
 runApp(new MaterialApp(
     home: new MyApp(),
 ),);


class MyApp extends StatefulWidget 
@override
_MyAppState createState() => new _MyAppState();
  

      class _MyAppState extends State<MyApp> 
 final TextEditingController _nameController = new TextEditingController();
 final TextEditingController _emailIdController = new 
 TextEditingController();
 final TextEditingController _passwordController = new 
 TextEditingController();
 final TextEditingController _confirmPasswordController = new 
 TextEditingController();

 MyModel myModel = new MyModel();

 @override
 Widget build(BuildContext context) 
  return new MaterialApp(
  home: new Scaffold(
    body: new ListView(

      children: <Widget>[
        new Container(
          child: new TextFormField(
            decoration: new InputDecoration(
              labelText: 'Enter your Name'
            ),
            controller: _nameController,
            onSaved: (String value)myModel.name = value; ,
          ),
        ),
        new Container(
          child: new TextFormField(
            decoration: new InputDecoration(
                labelText: 'EmailId'
            ),
              controller: _emailIdController,
              onSaved: (String value)myModel.emailId = value;
          ),
        ),
        new Container(
          child: new TextFormField(
            decoration: new InputDecoration(
                labelText: 'Password'
            ),
              controller: _passwordController,
              onSaved: (String value)myModel.password = value;
          ),
        ),
        new Container(
          child: new TextFormField(
            decoration: new InputDecoration(
                labelText: 'Confirm Password'
            ),
            controller: _confirmPasswordController,

          ),
        ),
        new Container(
          child: new FlatButton(
            onPressed: (()

              Navigator.push(context, new MaterialPageRoute(builder: (_) => 
         new SecondScreen(),),);

            ),
            child: new Text('Save'),),
        ),



      ],


      ),
     ),
    );
   
  

models.dart

class MyModel 

String name;
String emailId;
String password;

  

secondwidget.dart

 import 'package:flutter/material.dart';


 class SecondScreen extends StatefulWidget 
 @override
 _SecondScreenState createState() => new _SecondScreenState();


class _SecondScreenState extends State<SecondScreen> 
@override
Widget build(BuildContext context) 
return new MaterialApp(
  home: new Scaffold(
    body: new ListView(

      children: <Widget>[
        new Container(
          child: new TextFormField(
            decoration: new InputDecoration(
                labelText: 'Enter address'
            ),
          ),
        ),
        new Container(
          child: new TextFormField(
            decoration: new InputDecoration(
                labelText: 'Address Line 2'
            ),
          ),
        ),
        new Container(
          child: new TextFormField(
            decoration: new InputDecoration(
                labelText: 'Address Line 3'
            ),
          ),
        ),
        new Container(
          child: new TextFormField(
            decoration: new InputDecoration(
                labelText: 'POST CODE'
            ),
          ),
        ),

        new Container(
          child: new TextFormField(
            decoration: new InputDecoration(
                labelText: 'Mobile Number'
            ),
          ),
        ),
        new Container(
          child: new FlatButton(
              onPressed: (()


                //I want to push the data captured from main.dart and from 
                            //secondwidget.dart into database
     // I want to use the instance of MyModel from main.dart here to save 
      // the data captured from the first screen and this one into database

              ),
              child: new Text('Save'),),
        ),


      ],


    ),
  ),
);


【问题讨论】:

我不知道这里有什么问题,你可以简单地导入另一个 dart 文件,然后在另一个小部件中创建一个小部件的实例,如果你添加两者的代码会更好dart 文件,以便了解您要实现的目标,否则您的问题非常笼统且含糊。 非常感谢 aziza 我已经编辑了问题以准确显示我正在寻找的内容。但科林杰克逊提出了一个答案。所以我会先尝试一下,看看是否能解决我的问题。 Collin 建议的第三个选项在这里应该可以正常工作,您可以简单地将保存在第一页的TextForms 中的数据作为SecondScreen 的构造函数参数传递,然后使用它们来创建SecondScreen 中的模型对象。 【参考方案1】:

根据您的用例,有很多方法可以做到这一点。这里有几个选项:

    您可以将创建的对象公开为State 的公共成员。然后在一个State 中使用GlobalKeycurrentState 属性来获取对另一个State 的引用。现在您可以通过公共成员访问创建的对象。 (注意:这种模式限制了 State 的可测试性和封装性,因此请谨慎使用。) 两个小部件都可以有一个祖先小部件,它扩展了InheritedWidget,它们用于查找创建的对象。 两个小部件都可以在其构造函数中传递模型参数,例如ValueNotifier。他们可以使用此对象来读取和写入值。

如果您更详细地了解您的用例,我们可以帮助您选择一种有意义的模式。

这是一些实现选项 #1 的代码。

import 'package:flutter/material.dart';

void main() 
  runApp(new MyApp());


final key = new GlobalKey<MyStatefulWidget1State>();

class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return new MaterialApp(
      home: new Scaffold(
        body: new Column(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: <Widget>[
            new MyStatefulWidget1(key: key),
            new MyStatefulWidget2(),
          ],
        ),
      ),
    );
  


class MyStatefulWidget1 extends StatefulWidget 
  MyStatefulWidget1( Key key ) : super(key: key);
  State createState() => new MyStatefulWidget1State();


class MyStatefulWidget1State extends State<MyStatefulWidget1> 
  String _createdObject = "Hello world!";
  String get createdObject => _createdObject;

  @override
  Widget build(BuildContext context) 
    return new Center(
      child: new Text(_createdObject),
    );
  


class MyStatefulWidget2 extends StatefulWidget 
  State createState() => new MyStatefulWidget2State();


class MyStatefulWidget2State extends State<MyStatefulWidget2> 
  String _text = 'PRESS ME';

  @override
  Widget build(BuildContext context) 
    return new Center(
      child: new RaisedButton(
        child: new Text(_text),
        onPressed: () 
          setState(() 
            _text = key.currentState.createdObject;
          );
        ,
      ),
    );
  

【讨论】:

谢谢@Collin Jackson 这对我有用,谢谢你的帮助。 注意 key 是如何声明的。它应该是“final key = ...”或具有正确的泛型类型GlobalKey&lt;MyStatefulWidget1State&gt; key = ...。否则GlobalKey key = ... 你会得到GlobalKey&lt;State&lt;StatefulWidget&gt;&gt; 类型,它显然对createdObject 一无所知。这件事很容易被忽视。我做到了。 先生,当其他 statfull 小部件位于单独的文件中时,这不起作用。 嗨@CollinJackson 你能帮我处理一下我的案子吗?我有这个:eventform.dart => appbar:evenformappbar.dart,body:eventformbody.dart。 eventformbody.dart => 孩子:eventformform。我的保存/提交按钮在我的 eventformappbar.dart 中,我的提交功能在我的 eventformform.dart 中。如何从 eventformappbar.dart 访问 eventformform.dart 中的函数?请帮忙。谢谢。【参考方案2】:

您可以在构造SecondScreen小部件时传递模型。

    将模型添加到SecondScreen构造函数:

    class SecondScreen extends StatefulWidget 
      final MyModel myModel;
    
      SecondScreen(MyModel myModel, Key key):
          super(key: key);
    ...
    
    

    在 main.dart 中构造 SecondScreen 时传递模型

    Navigator.push(context, new MaterialPageRoute(builder: (_) => 
      new SecondScreen(model)));
    

    现在您可以通过widget.myModel 访问_SecondScreenState 中的模型

【讨论】:

谢谢@user559098,这也是解决我的问题的方法之一。 现在我可以看到 Mahi 的代码,我想这就是你想要的方法。【参考方案3】:

这是我将参数传递给子小部件的方式。

第一个 Widget dart 文件

class FirstWidget extends StatefulWidget 
    _FirstWidgetState createState() => _FirstWidgetState() 


class _FirstWidgetState extends State<FirstWidget> 
    String param = "My parameter";
    @override
    Widget build(BuildContext context) 
        return Container(
                    child: 
                        SecondWidget(param), //pass parmater here
                );
    

第二个 Widget dart 文件

class SecondWidget extends StatefulWidget 
    final String param; 
    SecondWidget(this.param); //passed paramter
    _SecondWidgetState createState() => _SecondWidgetState() 


class _SecondWidgetState extends State<SecondWidget> 
    @override
    Widget build(BuildContext context) 
        return Container(
                    child: 
                        Text(widget.param), //output paramter
                );
    

【讨论】:

最简单的解决方案,非常感谢! 非常感谢,对我帮助很大

以上是关于如何在颤动的另一个有状态小部件中访问在一个有状态小部件中创建的对象的主要内容,如果未能解决你的问题,请参考以下文章

如何从有状态的小部件类传递变量? - 颤动[重复]

为啥小部件的状态在颤动时没有改变?

如何从有状态小部件类 Flutter 访问小部件状态

setState 是不是会在颤动中为屏幕重建整个小部件树,以及它与其他状态管理相比如何

启动画面颤动,防止返回按钮

如何在颤动中从父小部件调用子小部件的initState()方法