Search code examples
androidflutterdartsetstatestream-builder

Correct way to manage state on dynamic widgets in Flutter


I have a list of categories in sqlite, I got those rows across streambuilder, then, I create a list of switch widgets. In each switch widget ontoggle event I change the source value and I call setState method, but, this causes the execution of the build event and reset all switch widgets values. After that I changed the code to store all widgets in a variable and in the streambuild if the widgets exists, return the widget list, this works almost well, this update the widgets values in sources, but, the widgets looks like if they were false.

Anyone has a clue?

Regards

           StreamBuilder<List<Category>>(   <--- this code is in build event
              stream: _catBloc.categoriesStream,
              builder: (BuildContext context, AsyncSnapshot<List<Category>> snapshot) {
                if(!snapshot.hasData) {
                  return Container(
                    height: _size.height,
                    width: _size.width,
                    child: Center(
                      child: CircularProgressIndicator(),
                    ),
                  );
                } else if(_categoriesLinked.isEmpty){ <-- this is a map with the list of id and name
                  column = _createCategories(snapshot.data, widthSwitch);
                  return column;
                 } else {
                   return column;
                 }
              },
            ),


Container(  <-- this is inside _createCategories method
      width: width,
      child: Row(
        children: [
          FlutterSwitch(
            width: _size.width * 0.06,
            height: _size.height * 0.02,
            toggleSize: 20.0,
            value: _categoriesLinked[e.id],
            showOnOff: false,
            padding: 2.0,
            activeColor: Color.fromRGBO(88, 203, 143, 0.25),
            inactiveColor: Color.fromRGBO(224, 233, 240, 0.50),
            activeToggleColor: Color.fromRGBO(88, 203, 143, 1.0),
            inactiveToggleColor: Color.fromRGBO(78, 88, 96, 0.50),
            onToggle: (val) => setState(() {
              _categoriesLinked[e.id] = val;
            }),
          ),
          SizedBox(width: _size.width * 0.01,),
          Flexible(child: Text("${ e.id}. ${ e.name}"))
        ]
      ),
    )

Solution

  • In this case, you should refactor your code in order to create the switch as another widget, making them rebuilding only themselves.

    For the state of the switch, you can simply get it from the parent using GlobalKey<MySwitchState> to access the children state during an onPressed method for example with: mySwitchKey.currentState

    You should definitely avoid building stateful widget inside methods. If you feel the need of a method, create a new widget.