代码之家  ›  专栏  ›  技术社区  ›  Ajay Kumar

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

  •  115
  • Ajay Kumar  · 技术社区  · 7 年前
    1. 例如,在下面的代码加上按钮工程和能够更新 文本,但减号按钮没有。
    2. 但如果我们按下FloatingActionButton,状态就会刷新。
    3. 减号按钮正在更改变量的值,但不会更改 正在更新父窗口小部件的状态。

    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 回复  |  直到 5 年前
        1
  •  213
  •   CopsOnRoad    5 年前

    1、在子窗口小部件上:添加参数函数parameter

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

    2、在父窗口小部件上:为子窗口小部件创建一个回调函数

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

    3、在父窗口小部件上:将parentFunction传递给子窗口小部件

    new ChildWidget( notifyParent: refresh );  
    

    4、在子窗口小部件上:调用父函数

      widget.notifyParent();
    
        2
  •  94
  •   CopsOnRoad    3 年前

    屏幕截图(父到子、子到父):

    enter image description here

    此示例显示如何调用方法

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

    代码:

    class ParentPage extends StatelessWidget {
      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: ElevatedButton(
                      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 VoidCallback function;
    
      ChildPage({Key? key, required 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: ElevatedButton(
            child: Text("Call method in parent"),
            onPressed: () => widget.function(), // calls method in parent
          ),
        );
      }
    
      methodInChild() => Fluttertoast.showToast(msg: "Method called in child");
    }
    
        3
  •  65
  •   Arnold Parge    3 年前

    旧的解决方案 :

    1. 创建\u MyHomePageState的全局实例。在子状态中使用此实例作为\u myHomePageState。设置状态
    2. 无需创建全局实例。相反,只需将父实例传递给子小部件

    新解决方案 :传递回调似乎是比上述解决方案更好的解决方案

    根据颤振2.0更新代码 :

    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(() {
                        this.number++;
                      });
                    },
                  ),
                  new Sub(onTap: () {
                    setState(() {
                      this.number--;
                    });
                  }),
                ],
              ),
            ],
          ),
          floatingActionButton: new FloatingActionButton(
            onPressed: () {
              setState(() {});
            },
            child: new Icon(Icons.update),
          ),
        );
      }
    }
    
    class Sub extends StatelessWidget {
      final Function onTap;
      Sub({this.onTap});
    
      @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.onTap,
        );
      }
    }
    

    只要让我知道它是否有效。

        4
  •  19
  •   Mohammad Ersan    5 年前

    如果你需要的话,我想延长穆罕默德·埃尔拉希德的回答 将变量从子小部件传递到父小部件

    在子窗口小部件上:

    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);
    
        5
  •  5
  •   Aman Bindlish    4 年前

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

    var ancestralState = context.findAncestorStateOfType<ParentState>();
          ancestralState.setState(() {
            // here you can access public vars and update state.
            ...
          });
    
        6
  •  4
  •   Vicky Salunkhe    4 年前

    这是对我有效的解决方案。

    输出: 购物车小部件的状态在添加项目后更新。

    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"),
               );
      }
    }
    
        7
  •  3
  •   user112380    3 年前
    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
                  )
         );
      }
    
    }
    
        8
  •  2
  •   Jacobo Koenig    5 年前

    虽然前面的大多数答案都可以,但我建议您探索提供商或集团架构,这两种架构都是谷歌推荐的。

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

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