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

Aja*_*mar 22 state flutter

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

在此输入图像描述

这是代码.....

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;
        });
      },
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

Moh*_*hid 41

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

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

2.On Parent Widget:为子进程创建一个回调函数

refresh() {
  setState(() {});
}
Run Code Online (Sandbox Code Playgroud)

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

new ChildWidget( notifyParent: refresh );  
Run Code Online (Sandbox Code Playgroud)

4.On Child Widget:调用Parent Function

  widget.notifyParent();
Run Code Online (Sandbox Code Playgroud)

  • 我该怎么做相反。我想从父母那里更新孩子 (13认同)
  • 如果孩子是一个有状态的小部件并且我想从父母那里更新它怎么办? (3认同)
  • 这是“假设的”解决方案吗?这是flutter团队用的吗?我在该代码中嗅到了问题的味道。或者也许只是我的鼻子太敏感了:D (3认同)
  • 对于那些想要将值“传递”到子窗口小部件的人,您可以在父窗口小部件中创建“ValueNotifier”,并将其传递给子窗口小部件。在您的子小部件中,利用“ValueListenableBuilder”来构建布局。 (3认同)
  • @Farhana 刷新(参数1,参数1){etState((){});} | widget.notifyParent(1,2); (2认同)

Arn*_*rge 22

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 --;
        });
      },
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

请告诉我它是否有效.

  • @RémiRousselet祖先StateOfType 方法在 v1.12.1 后已被弃用。使用“findAncestorStateOfType”代替https://api.flutter.dev/flutter/widgets/BuildContext/findAncestorStateOfType.html (3认同)
  • 工作但很糟糕.至少,使用诸如`context.ancestorStateOfType`之类的东西 (2认同)
  • @RémiRousselet你能举一个如何使用它的例子吗? (2认同)

Alv*_*nda 14

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

在子小部件上:

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

在父小部件上

void refresh(dynamic childValue) {
  setState(() {
    _parentVariable = childValue;
  });
}
Run Code Online (Sandbox Code Playgroud)

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

new ChildWidget( notifyParent: refresh ); 
Run Code Online (Sandbox Code Playgroud)

在子小部件上:使用来自子小部件的任何变量调用父函数

widget.notifyParent(childVariable);
Run Code Online (Sandbox Code Playgroud)


小智 9

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

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


Cop*_*oad 7

在此处输入图片说明

此示例显示了调用方法

  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");
}
Run Code Online (Sandbox Code Playgroud)

  • 与其他答案相比,我发现这很有帮助 (3认同)
  • 最终 GlobalKey&lt;_ChildPageState&gt; _key = GlobalKey(); _ChildPageState 不是类型,因此它不能作为类型参数? (2认同)
  • 从 _ChildPageState 中删除 _,下划线 _ 表示该类是私有的。 (2认同)
  • 我喜欢这种方法,还要添加一件事是处理 _key.currentState 并检查它是否不为空。 (2认同)

小智 7

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
              )
     );
  }

}
Run Code Online (Sandbox Code Playgroud)

  • 请为您的答案提供一些背景信息。它可以帮助该问题的其他访问者轻松理解您的方法。 (3认同)

Vic*_*khe 5

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

输出: 添加商品后,购物车状态小组件会更新。

在此输入图像描述

globalKey通过调用以下命令为要更新的小部件创建一个trigger from anywhere

final GlobalKey<CartWidgetState> cartKey = GlobalKey();
Run Code Online (Sandbox Code Playgroud)

确保它保存在具有全局访问权限的文件中,以便可以从任何地方访问它。我将其保存在 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();
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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"),
           );
  }
}
Run Code Online (Sandbox Code Playgroud)