颤振setstate仅重建一个孩子

时间:2019-11-04 11:25:57

标签: flutter dart flutter-layout

在扑朔迷离中,我需要在调用setstate时仅重建一个小部件

我将2个孩子堆叠在一起,我需要在按下按钮时,仅重建第二个孩子。

bool popup = false;

Scaffold(
  appBar: AppBar(
    title: const Text('TEST'),
    actions: <Widget>[
      IconButton(                       // + BUTTON
        icon: Icon(Icons.add),
        onPressed: () {
          setState(() {
            popup = true;
          });
        },
      ),
      IconButton(                       // - BUTTON
        icon: Icon(Icons.remove),
        onPressed: () {
          setState(() {
            popup = false;
          });
      ),
    ],
  ),
  body: SafeArea(
    child: Stack(
      children: <Widget>[

        Container(                                        // FIRST WIDGET
          key: ValueKey(1),
          child: Text("Random - "+new Random().nextInt(20).toString())
        ),

        popup ? Center(child: Text("abc")) : Text("") ,   // SECOND WIDGET

      ],

    ),
  ),
);

我希望当我按下“ +”按钮时,只会重新构建第二个小部件,但是现在它将重新构建堆栈的所有内容。

谢谢大家。

4 个答案:

答案 0 :(得分:0)

从您不想更改的小部件中删除setState。并且只将setState用于您需要重建的那些

或者您可以考虑使用InheritedModel小部件

答案 1 :(得分:0)

这里是一个示例,您可以在其中学习如何构建继承的模型小部件以仅更新特定的小部件而不是整个小部件。

https://medium.com/flutter-community/flutter-state-management-setstate-fn-is-the-easiest-and-the-most-powerful-44703c97f035

答案 2 :(得分:0)

您可以使用StreamBuilder:

  StreamController<bool> popup = StreamController<bool>();

  @override
  void dispose() {
    popup.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('TEST'),
        actions: <Widget>[
          IconButton(                       // + BUTTON
            icon: Icon(Icons.add),
            onPressed: () => popup.add(true),
          ),
          IconButton(                       // - BUTTON
            icon: Icon(Icons.remove),
            onPressed: () => popup.add(false),
          ),
        ],
      ),
      body: SafeArea(
        child: Stack(
          children: <Widget>[
            Container(                                        // FIRST WIDGET
              key: ValueKey(1),
              child: Text("Random - "+new Random().nextInt(20).toString())
            ),
            StreamBuilder<bool>(
              stream: popup.stream,
              initialData: false,
              builder: (cxt, snapshot) {
                return snapshot.data ? Center(child: Text("abc")) : Text("");
              },
            )
          ],

        ),
      ),
    );
  }

答案 3 :(得分:0)

official docs我们可以读到:

“在状态上调用setState()时,所有后代小部件都将重建。因此,请将setState()本地化为实际上需要更改UI的子树部分。避免将setState()向上调用如果更改只包含在树的一小部分,则在树中显示。”

我的建议(我经常使用)是将您要在新的StatefulWidget中重建的小部件分开。这样,仅setState将重新构建该小部件。

    class MyAppBar extends StatefulWidget
    ...
    class _MyAppBarState extends State<MyAppBar> {
    bool popup = false;

     @override
      Widget build(BuildContext context) {
        return AppBar(
           title: const Text('TEST'),
           actions: <Widget>[
           IconButton(                       // + BUTTON
             icon: Icon(Icons.add),
             onPressed: () {
               setState(() {
               popup = true;
             });
            },
           ),
          IconButton(                       // - BUTTON
            icon: Icon(Icons.remove),
            onPressed: () {
              setState(() {
              popup = false;
            });
          ),
        ],
       ), 
      }

然后在您的支架中调用它:

Scaffold(
  appBar: MyAppBar(), 

我建议使用的其他方法是使用 ValueNotifier notifyListeners()。请阅读此页面Avoid rebuilding all the widgets repetitively。解释得很好。