-2

I have a dialog box which is a stateful widget with multiple tabs wrapped inside Animated Switcher. Inside it I have a button which on clicked calls a function switchPage() which has a switch statement with each case setting the state of Widget? currentTab variable to a different one. The problem here arrives when I use this switchPage() function to change the value of currentTab to a different widget also wrapped in a different method getWidget2()

The code for the Example on DartPad

Try clicking as I suggest...

  • Click Floating Button.
  • Click on the first checkbox.
  • Now click on PAGE 2 button.
  • Click the second checkbox only once. Now notice the checkbox doesn't work when clicked.
  • Click PAGE 1 again to go the working checkbox.
  • Now click on PAGE 2 button again. The Checkbox value and state did change but did not update the time it was clicked, but it has updated when we forcefully re visited the checkbox.

I cannot find solution to this anywhere and I really need the code structure to be as optimized as possible. Please, if anyone has any explanation or any suggestions, it would be greatly appreciated..

Thanks, in advance.

  • Where is the code? – stacktrace2234 Sep 04 '21 at 16:09
  • Your inner widgets are stateless while the DemoDialog widget is stateful. I would change your code in a way that the setState action is only triggered from your stateful dialog and not your stateless widgets. Meaning, each time a checkbox is interacted with, the action is delegated to the stateful widget and not inside the inner widgets. I think that is the main reason your UI is not being updated. – tomerpacific Sep 04 '21 at 16:10
  • Hello @tomerpacific can you please give me an example of what you mean? I really cannot understand the problem.. – Megabyte Dev Sep 04 '21 at 16:17

1 Answers1

0

This is a very rough working example, but you can build upon it. In the code below, you can see that I have created two methods that handle setting the state of the checkbox for each widget. I have also reset the page once this method is triggered. What this does, is trigger the redrawing of the inner widgets (which is what I explained in my comment).

    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'))
          ],
        ),
      ),
    );
  }
}

This is just an example that makes things work, but it in no way represents how you should build things appropriately. I would look into separating the code into stateless and stateful widgets.

tomerpacific
  • 4,704
  • 13
  • 34
  • 52
  • Wow, thanks for the help buddy, didn't think of it this way. I'm gonna build upon this code as I have a lot of those checkboxes in ```getWidget2()``` method. Is this problem occurring because I'm creating widgets as a function? Does this make the widgets lose state? – Megabyte Dev Sep 04 '21 at 18:57
  • The problem occurs, because when you call setState it does not trigger the redrawing of your inner widgets (which is what you want). I would suggest you read more about stateless/ful widgets and how to design them so that they will benefit from being redrawn when setState is called. Plus, I don't know what the purpose of your application is, so there could half a dozen ways to do what you want. – tomerpacific Sep 04 '21 at 20:08