【问题标题】:setState is not updating UI in FluttersetState 没有在 Flutter 中更新 UI
【发布时间】:2021-09-04 16:04:51
【问题描述】:

我有一个对话框,它是一个有状态的小部件,其中包含多个选项卡,包含在 Animated Switcher 中。 在它里面我有一个按钮,点击它会调用一个函数switchPage(),它有一个switch语句,每种情况都将Widget? currentTab变量的状态设置为不同的状态。 当我使用这个switchPage() 函数将currentTab 的值更改为另一个也包装在不同方法getWidget2() 中的小部件时,问题就来了。

代码 Example on DartPad

按照我的建议尝试点击...

  • 点击浮动按钮。
  • 点击第一个复选框。
  • 现在点击PAGE 2按钮。
  • 仅单击第二个复选框一次。现在请注意,该复选框在单击时不起作用。
  • 再次单击PAGE 1 进入工作复选框。
  • 现在再次单击PAGE 2 按钮。 Checkbox 的值和状态确实发生了变化,但没有更新它被点击的时间,但是当我们强制重新访问该复选框时它已经更新了。

我在任何地方都找不到解决方案,我真的需要尽可能优化代码结构。 请,如果有人有任何解释或任何建议,将不胜感激..

谢谢,提前。

【问题讨论】:

  • 代码在哪里?
  • 您的内部小部件是无状态的,而 DemoDialog 小部件是有状态的。我将更改您的代码,使 setState 操作仅从您的有状态对话框而不是您的无状态小部件触发。这意味着,每次与复选框交互时,该操作都会委托给有状态的小部件,而不是内部小部件。我认为这是您的 UI 没有更新的主要原因。
  • 你好@tomerpacific 你能给我一个例子来说明你的意思吗?我真的无法理解这个问题..

标签: flutter dart flutter-state


【解决方案1】:

这是一个非常粗略的工作示例,但您可以在此基础上进行构建。 在下面的代码中,您可以看到我创建了两个方法来处理为每个小部件设置复选框的状态。触发此方法后,我还重置了页面。这样做的目的是触发内部小部件的重绘(这是我在评论中解释的)。

    class _DemoDialogState extends State<DemoDialog> {
    Widget? currentTab;

    bool valueOfCheckbox1 = false;
    bool valueOfCheckbox2 = false;

    void switchPage(name) {
    switch (name) {
      case 1:
        setState(() {
          currentTab = getWidget1(setCheckbox1State);  // <---- Notice the change here
        });
        break;

      case 2:
        setState(() {
          currentTab = getWidget2(setCheckbox2State);  // <---- Notice the change here
        });
        break;
      }
    }
  
    void setCheckbox1State(bool? newState) {
    if (newState != null) {
       setState(() {  // <---- Notice the change here
        valueOfCheckbox1 = newState;
         currentTab = getWidget1(setCheckbox1State);
      });
    }
    
   }
  
    void setCheckbox2State(bool? newState) {
      if (newState != null) {
       setState(() {  // <---- Notice the change here
        valueOfCheckbox2 = newState;
         currentTab = getWidget2(setCheckbox2State);
      });
     }
    }

  

    Widget getWidget1(Function(bool?) checkboxFunction) {
        return Container(
            child: Row(
          children: [
            Text('Hello from widget 1'),
            Checkbox(
                value: valueOfCheckbox1,
                onChanged: (value) {  // <---- Notice the change here
                  checkboxFunction(value);
                })
          ],
        ));
      }
    
      Widget getWidget2(Function(bool?) checkboxFunction) {
        return Container(
            child: Row(
          children: [
            Text('Hello from widget 2'),
            Checkbox(
                value: valueOfCheckbox2,
                onChanged: (value) {  // <---- Notice the change here
                  checkboxFunction(value);
                })
          ],
        ));
      }

      @override
       Widget build(BuildContext context) {
    return Dialog(
      child: Container(
        width: 280,
        height: 600,
        color: Colors.white,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: [
            AnimatedSwitcher(
              duration: Duration(milliseconds: 250),
              reverseDuration: Duration(milliseconds: 250),
              transitionBuilder: (child, animation) {
                var begin = Offset(0.5, 0);
                var end = Offset.zero;
                var curve = Curves.easeIn;
                var tween = Tween(begin: begin, end: end)
                    .chain(CurveTween(curve: curve));

                var begin2 = 0.0;
                var end2 = 1.0;
                var curve2 = Curves.easeIn;
                var tween2 = Tween(begin: begin2, end: end2)
                    .chain(CurveTween(curve: curve2));

                return SlideTransition(
                  position: animation.drive(tween),
                  child: FadeTransition(
                      opacity: animation.drive(tween2), child: child),
                );
              },
              layoutBuilder: (widget, list) {
                return Align(
                  alignment: Alignment.topCenter,
                  child: widget,
                );
              },  // <---- Notice the change here
              child: currentTab == null ? getWidget1(setCheckbox1State) : currentTab,
            ),
            TextButton(
                onPressed: () {
                  switchPage(1);
                },
                child: Text('PAGE 1')),
            TextButton(
                onPressed: () {
                  switchPage(2);
                },
                child: Text('PAGE 2'))
          ],
        ),
      ),
    );
  }
}

这只是一个让事情发挥作用的例子,但它绝不代表你应该如何适当地构建事情。我会考虑将代码分成无状态和有状态的小部件。

【讨论】:

  • 哇,谢谢哥们的帮助,没想到是这样的。我将在此代码的基础上进行构建,因为我在 getWidget2() 方法中有很多这些复选框。是否因为我将小部件创建为函数而出现此问题?这是否会使小部件失去状态?
  • 出现问题,因为当您调用 setState 时,它​​不会触发内部小部件的重绘(这是您想要的)。我建议您阅读更多关于无状态/ ful 小部件以及如何设计它们的信息,以便在调用 setState 时重绘它们。另外,我不知道你的应用程序的目的是什么,所以可以有六种方法来做你想做的事。
猜你喜欢
  • 2021-10-07
  • 2022-01-07
  • 2021-09-06
  • 2020-12-17
  • 1970-01-01
  • 2020-12-09
  • 2021-11-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多