flutter setstate 只重建一个孩子

Joh*_*ohn 3 dart flutter flutter-layout

在flutter中我需要当我调用setstate时,它只重建一个小部件

我将两个孩子放在一堆中,我需要当按下按钮时,只重建第二个孩子。

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

      ],

    ),
  ),
);
Run Code Online (Sandbox Code Playgroud)

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

谢谢你们。

Ric*_*rdd 5

官方文档我们可以读到:

“当在 State 上调用 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;
            });
          ),
        ],
       ), 
      }
Run Code Online (Sandbox Code Playgroud)

然后在你的脚手架中调用它:

Scaffold(
  appBar: MyAppBar(), 
Run Code Online (Sandbox Code Playgroud)

我可以建议的其他方法是使用ValueNotifiernotifyListeners()。请阅读此页避免重复重建所有小部件。这是很好解释的。


Nic*_*nko 5

另一种选择是使用 ValueListenableBuilder:

class _MyHomePageState extends State<MyHomePage> {
  final ValueNotifier<bool> popup = ValueNotifier<bool>(false);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('TEST'),
        actions: <Widget>[
          IconButton(
              // + BUTTON
              icon: Icon(Icons.add),
              onPressed: () {
                popup.value = true;
              }),
          IconButton(
              // - BUTTON
              icon: Icon(Icons.remove),
              onPressed: () {
                popup.value = false;
              })
        ],
      ),
      body: Center(
        child: ValueListenableBuilder<bool>(
            valueListenable: popup,
            builder: (context, value, _) {
              return Stack(
                children: [
                  Text("Random - " + new Random().nextInt(20).toString()),
                  popup.value ? Center(child: Text("abc")) : Text(""),
                ],
              );
            }),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)