如何从Flutter中的其他StatefulWidget设置/更新StatefulWidget的状态?

时间:2018-01-27 23:22:18

标签: state flutter

  1. 例如,下面的代码加按钮工作并能够更新 文本但减号按钮没有。
  2. 但是如果我们按下FloatingActionButton,那么状态就会刷新。
  3. 减号按钮正在更改变量的值,但不是 更新父窗口小部件的状态。
  4. enter image description here

    这里是代码.....

    import 'package:flutter/material.dart';
    
    void main() => runApp(new MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          title: 'Flutter Demo',
          theme: new ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: new MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    int number;
    
    EdgeInsets globalMargin = const EdgeInsets.symmetric(horizontal: 20.0, vertical: 20.0);
    TextStyle textStyle = const TextStyle(
      fontSize: 100.0,
      color: Colors.black,
    );
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
    
      final String title;
    
      @override
      _MyHomePageState createState() => new _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      @override
      void initState() {
        super.initState();
        number = number ?? 0;
      }
    
      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          appBar: new AppBar(
            title: new Text(widget.title),
          ),
          body: new Column(
            children: <Widget>[
              new Text(
                number.toString(),
                style: textStyle,
              ),
              new GridView.count(
                crossAxisCount: 2,
                shrinkWrap: true,
                scrollDirection: Axis.vertical,
                children: <Widget>[
                  new InkResponse(
                    child: new Container(
                        margin: globalMargin,
                        color: Colors.green,
                        child: new Center(
                          child: new Text(
                            "+",
                            style: textStyle,
                          ),
                        )),
                    onTap: () {
                      setState(() {
                        number = number + 1;
                      });
                    },
                  ),
                  new Sub(),
                ],
              ),
            ],
          ),
          floatingActionButton: new FloatingActionButton(
            onPressed: () {
              setState(() {});
            },
            child: new Icon(Icons.update),
          ),
        );
      }
    }
    
    class Sub extends StatefulWidget {
      @override
      _SubState createState() => new _SubState();
    }
    
    class _SubState extends State<Sub> {
      @override
      Widget build(BuildContext context) {
        return new InkResponse(
          child: new Container(
              margin: globalMargin,
              color: Colors.red,
              child: new Center(
                child: new Text(
                  "-",
                  style: textStyle,
                ),
              )),
          onTap: () {
            setState(() {
              number = number - 1;
            });
          },
        );
      }
    }
    

8 个答案:

答案 0 :(得分:21)

1.On Child Widget:添加参数Function paramter

class ChildWidget extends StatefulWidget {
  final Function() notifyParent;
  ChildWidget({Key key, @required this.notifyParent}) : super(key: key);
}

2。在“父级小部件”上:为孩子创建一个回调函数

refresh() {
  setState(() {});
}

3。在Parent Widget上:将parentFunction传递给Child Widget

new ChildWidget( notifyParent: refresh );  

4.On Child Widget:调用父函数

  widget.notifyParent();

答案 1 :(得分:18)

OLD :创建_MyHomePageState的全局实例。在_SubState中将此实例用作_myHomePageState.setState

:无需创建全局实例。而只是将父实例传递给子窗口小部件

代码更新为每个FLUTTER 0.8.2

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(),
    );
  }
}

EdgeInsets globalMargin =
    const EdgeInsets.symmetric(horizontal: 20.0, vertical: 20.0);
TextStyle textStyle = const TextStyle(
  fontSize: 100.0,
  color: Colors.black,
);

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int number = 0;

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('SO Help'),
      ),
      body: new Column(
        children: <Widget>[
          new Text(
            number.toString(),
            style: textStyle,
          ),
          new GridView.count(
            crossAxisCount: 2,
            shrinkWrap: true,
            scrollDirection: Axis.vertical,
            children: <Widget>[
              new InkResponse(
                child: new Container(
                    margin: globalMargin,
                    color: Colors.green,
                    child: new Center(
                      child: new Text(
                        "+",
                        style: textStyle,
                      ),
                    )),
                onTap: () {
                  setState(() {
                    number = number + 1;
                  });
                },
              ),
              new Sub(this),
            ],
          ),
        ],
      ),
      floatingActionButton: new FloatingActionButton(
        onPressed: () {
          setState(() {});
        },
        child: new Icon(Icons.update),
      ),
    );
  }
}

class Sub extends StatelessWidget {

  _MyHomePageState parent;

  Sub(this.parent);

  @override
  Widget build(BuildContext context) {
    return new InkResponse(
      child: new Container(
          margin: globalMargin,
          color: Colors.red,
          child: new Center(
            child: new Text(
              "-",
              style: textStyle,
            ),
          )),
      onTap: () {
        this.parent.setState(() {
          this.parent.number --;
        });
      },
    );
  }
}

请告诉我它是否有效。

答案 2 :(得分:10)

enter image description here

此示例显示了调用方法

  1. 在“父”窗口小部件的“子”窗口小部件中定义。
  2. 在“子级”小部件中的“父级”小部件中定义。

class ParentPage extends StatefulWidget {
  @override
  _ParentPageState createState() => _ParentPageState();
}

class _ParentPageState extends State<ParentPage> {
  final GlobalKey<_ChildPageState> _key = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Parent")),
      body: Center(
        child: Column(
          children: <Widget>[
            Expanded(
              child: Container(
                color: Colors.grey,
                width: double.infinity,
                alignment: Alignment.center,
                child: RaisedButton(
                  child: Text("Call method in child"),
                  onPressed: () => _key.currentState.methodInChild(), // calls method in child
                ),
              ),
            ),
            Text("Above = Parent\nBelow = Child"),
            Expanded(
              child: ChildPage(
                key: _key,
                function: methodInParent,
              ),
            ),
          ],
        ),
      ),
    );
  }

  methodInParent() => Fluttertoast.showToast(msg: "Method called in parent", gravity: ToastGravity.CENTER);
}

class ChildPage extends StatefulWidget {
  final Function function;

  ChildPage({Key key, this.function}) : super(key: key);

  @override
  _ChildPageState createState() => _ChildPageState();
}

class _ChildPageState extends State<ChildPage> {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.teal,
      width: double.infinity,
      alignment: Alignment.center,
      child: RaisedButton(
        child: Text("Call method in parent"),
        onPressed: () => widget.function(), // calls method in parent
      ),
    );
  }

  methodInChild() => Fluttertoast.showToast(msg: "Method called in child");
}

答案 3 :(得分:2)

旧的,但我会根据发现添加答案:

var ancestralState = context.findAncestorStateOfType<ParentState>();
      ancestralState.setState(() {
        // here you can access public vars and update state.
        ...
      });

答案 4 :(得分:1)

class HomePage extends StatefulWidget {

  @override
  HomePageState createState() => HomePageState();
}

class HomePageState extends State<HomePage> {

  int selectedIndex = 0;

   void setSelectedIndex(int index){
     setState(() {
      selectedIndex = index;
     });
  }
}

class TestPage extends StatefulWidget {

  @override
  TestPageState createState() => TestPageState();
}

class TestPageState extends State<TestPage> {
  int selectedIndex = 0;

  @override
  Widget build(BuildContext context) {
     return  GestureDetector(
                      onTap: (){

                        final HomePageState state = context.findAncestorStateOfType<HomePageState>();

                        state.setSelectedIndex(4);

                      },
                    child: Container(
                        width: 100,
                        height: 100,
                        color: Colors.green
              )
     );
  }

}

答案 5 :(得分:0)

我想扩展Mohamed Elrashid的答案,以防您需要将变量从子窗口小部件传递到父窗口小部件

在子窗口小部件上:

class ChildWidget extends StatefulWidget {
  final Function() notifyParent;
  ChildWidget({Key key, @required this.notifyParent}) : super(key: key);
}

在父窗口小部件上

void refresh(dynamic childValue) {
  setState(() {
    _parentVariable = childValue;
  });
}

在父窗口小部件上:将上面的函数传递给子窗口小部件

new ChildWidget( notifyParent: refresh ); 

在子窗口小部件上:使用子窗口小部件中的任何变量调用父函数

widget.notifyParent(childVariable);

答案 6 :(得分:0)

尽管以上大多数答案都可以使用,但我建议您探索Google推荐的提供商或BloC体系结构。

简而言之,后者将创建一个流,当状态发生变化时,该流将向窗口小部件树中的窗口小部件报告,并且它将更新所有相关视图,无论从何处更新。

这是一个很好的概述,您可以阅读以了解有关该主题的更多信息:https://bloclibrary.dev/#/

答案 7 :(得分:0)

以下是对我有用的解决方案。

输出: 添加物品后,购物车小部件的状态也会更新。

enter image description here

通过调用globalKey为要更新的小部件创建trigger from anywhere

final GlobalKey<CartWidgetState> cartKey = GlobalKey();

确保将其保存在文件中具有全局访问权限,以便可以从任何位置访问它。 我将其保存在globalClass中,该位置通过应用程序的状态保存常用变量。

class CartWidget extends StatefulWidget {

  CartWidget({Key key}) : super(key: key);
  @override
  CartWidgetState createState() => CartWidgetState();
}

class CartWidgetState extends State<CartWidget> {
  @override
  Widget build(BuildContext context) {
    //return your widget
    return Container();
  }
}

从其他类调用您的小部件。

class HomeScreen extends StatefulWidget {

  HomeScreen ({Key key}) : super(key: key);
  @override
  HomeScreenState createState() => HomeScreen State();
}

class HomeScreen State extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    return ListView(
              children:[
                 ChildScreen(), 
                 CartWidget(key:cartKey)
              ]
            );
  }
}



class ChildScreen extends StatefulWidget {

  ChildScreen ({Key key}) : super(key: key);
  @override
  ChildScreenState createState() => ChildScreen State();
}

class ChildScreen State extends State<ChildScreen> {
  @override
  Widget build(BuildContext context) {
    return InkWell(
              onTap: (){
                // This will update the state of your inherited widget/ class
                if (cartKey.currentState != null)
                    cartKey.currentState.setState(() {});
              },
              child: Text("Update The State of external Widget"),
           );
  }
}