【问题标题】:Emit the data to parent Widget in Flutter在 Flutter 中向父 Widget 发送数据
【发布时间】:2018-12-30 00:38:48
【问题描述】:

我正在尝试将文本从子小部件设置为父小部件。但是文本没有反映在父小部件中。

也尝试使用 setState() 但仍然无法获得预期的结果。

以下是我的代码:

void main() => runApp(new TestApp());

class TestApp extends StatefulWidget {
  @override
  _TestState createState() => new _TestState();
}

class _TestState extends State<TestApp>{

  String abc = "";

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new Scaffold(
        body: new Column(
          children: <Widget>[
            new Text("This is text $abc"),
            TestApp2(abc)
          ],
        ),
      ),
    );
  }
}


class TestApp2 extends StatefulWidget {

  String abc;

  TestApp2(this.abc);

  @override
  _TestState2 createState() => new _TestState2();
}

class _TestState2 extends State<TestApp2>{
  @override
  Widget build(BuildContext context) {
    return new Container(
      width: 150.0,
      height: 30.0,
      margin: EdgeInsets.only(top: 50.0),
      child: new FlatButton(
          onPressed: (){
            setState(() {
              widget.abc = "RANDON TEXT";
            });
          },
        child: new Text("BUTTON"),
        color: Colors.red,
      ),
    );
  }
}

我错过了什么吗?

【问题讨论】:

标签: dart flutter


【解决方案1】:

在您的示例中,做了一些假设。我会尝试一一删除。

  1. 您将abc 从父级传递给子级,并在按下按钮时改变了子级值。由于原始类型在 dart 中是按值传递,因此更改子中 abc 的值不会更改父 abc 的值。参考下面的sn-p。

    void main() {
      String abc = "oldValue";
      changeIt(abc);
      print(abc); // oldValue
    }
    
    void changeIt(String abc) {
      abc = "newValue";
      print(abc); //newValue
    }
    
  2. 让我们假设第一个是错误的(为了理解目的)。然后更改子中abc 的值将更改父中abc 的值。但是如果没有在父级的setState 内调用它,父级将不会反映更改。在您的情况下,如果您更改如下代码,它将在单击时单独更改按钮文本(因为 setState of child 被调用)。

      new FlatButton(
        onPressed: () {
          setState(
            () {
              widget.abc = "RANDON TEXT";
            },
          );
        },
        child:
            new Text(widget.abc), // setting the text based on abc
        color: Colors.red,
      ),
    
  3. 我建议使用callbacks,而不是使用globalState,因为随着应用程序的增长,这将很难维护/调试。请参考以下代码。

        void main() => runApp(new TestApp());
    
        class TestApp extends StatefulWidget {
          @override
          _TestState createState() => new _TestState();
        }
    
        class _TestState extends State<TestApp> {
          String abc = "bb";
    
          callback(newAbc) {
            setState(() {
              abc = newAbc;
            });
          }
    
          @override
          Widget build(BuildContext context) {
            var column = new Column(
              children: <Widget>[
                new Text("This is text $abc"),
                TestApp2(abc, callback)
              ],
            );
            return new MaterialApp(
              home: new Scaffold(
                body: new Padding(padding: EdgeInsets.all(30.0), child: column),
              ),
            );
          }
        }
    
        class TestApp2 extends StatefulWidget {
          String abc;
          Function(String) callback;
    
          TestApp2(this.abc, this.callback);
    
          @override
          _TestState2 createState() => new _TestState2();
        }
    
        class _TestState2 extends State<TestApp2> {
          @override
          Widget build(BuildContext context) {
            return new Container(
              width: 150.0,
              height: 30.0,
              margin: EdgeInsets.only(top: 50.0),
              child: new FlatButton(
                onPressed: () {
                  widget.callback("RANDON TEXT"); //call to parent
                },
                child: new Text(widget.abc),
                color: Colors.red,
              ),
            );
          }
        }
    

【讨论】:

  • 还有一个疑问! Redux 在这种情况下有用吗?
  • 谢谢它对我有用,尽管我不得不将 TestApp2 的类变量从“String abc;Function(String) callback;”更改为到“最终 abc;最终回调;”
  • 很棒的解决方案。
  • 为什么我们不能给答案打星?
  • 我必须在构建函数中声明回调,否则我会出现以下错误:“只有静态成员可以在初始化程序中访问”
【解决方案2】:

您缺少的一点是您的 setState 方法调用。您调用TestState2 的setState。

要解决这个问题,有两种方法。

第一种方法是创建一个 GlobalKey(https://docs.flutter.io/flutter/widgets/GlobalKey-class.html) 并将其作为参数传递给子小部件。

而第二种方式是为父状态创建一个全局变量,并在子状态中使用。

我用第二种方法修改了下面的代码。

_TestState _globalState = new _TestState();

class TestApp extends StatefulWidget {
  @override
  _TestState createState() => _globalState;
}

class _TestState extends State<TestApp>{

  String abc = "";

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new Scaffold(
        body: new Column(
          children: <Widget>[
            new Text("This is text $abc"),
            TestApp2()
          ],
        ),
      ),
    );
  }
}


class TestApp2 extends StatefulWidget {

  TestApp2();

  @override
  _TestState2 createState() => new _TestState2();
}

class _TestState2 extends State<TestApp2>{
  @override
  Widget build(BuildContext context) {
    return new Container(
      width: 150.0,
      height: 30.0,
      margin: EdgeInsets.only(top: 50.0),
      child: new FlatButton(
        onPressed: (){
          _globalState.setState((){
            _globalState.abc = "Button clicked";
          });
        },
        child: new Text("BUTTON"),
        color: Colors.red,
      ),
    );
  }
}

【讨论】:

    【解决方案3】:

    写出非常准确的答案。只需像上面的答案一样使用回调使用这个。 所以你想从另一个函数/小部件/类调用 ​​ParentScreen 的状态。只需遵循此代码

    import 'package:showErrorMessage.dart';
    
    class ParentScreen extends StatefulWidget {
      ParentScreen({Key key}) : super(key: key);
    
      @override
      _ParentScreenState createState() => _ParentScreenState();
    }
    
    class _ParentScreenState extends State<ParentScreen> {
    
       callback() {
        setState(() {});
      }
      
      @override
      Widget build(BuildContext context) {
        String message = "hello";
        return Container(
           child: showErrorMessage(message, callback);,
        );
      }
    }
    

    这是子小部件/函数/类

    import 'package:flutter/material.dart';
    
    
        showErrorMessage(message, Function callback) {
          return Center(
          child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Text(
            message,
            style: TextStyle(color: Colors.white, fontSize: 16),
          ),
          GestureDetector(
              onTap: () {
                callback();  // ------ this will change/rebuild the state of its parent class
              },
              child: Icon(
                Icons.refresh,
                size: 30,
                color: Colors.white,
              )),
        ],
      ));
    }
    

    【讨论】:

      猜你喜欢
      • 2020-02-11
      • 2021-08-09
      • 1970-01-01
      • 1970-01-01
      • 2023-03-31
      • 2022-10-07
      • 1970-01-01
      • 2020-03-28
      • 1970-01-01
      相关资源
      最近更新 更多