Search code examples
flutterdartbuildsetstate

flutter message 'setState() or markNeedsBuild() called during build'


I have a problem with the following code. I get here the message 'setState() or markNeedsBuild() called during build' and I don't know what to do to make the code run correctly. The idea is to create a list that stores the index of the activated ToggleButton to generate a display of the same information on a different screen in different places. Thanks a lot for the help.

If more code or information is needed I will be happy to post it.


class ToggleButtonUsers extends StatefulWidget {
  @override
  _ToggleButtonUsersState createState() => _ToggleButtonUsersState();
}

class _ToggleButtonUsersState extends State<ToggleButtonUsers> {
  bool vertical = false;
  List<bool> selectedUser = [];
  List<Widget> selectedChildren = [];

  @override
  void initState() {
    final userModelData = Provider.of<UserModel>(context, listen: false);
    final userModel = userModelData.items;
    final toggleModelData = Provider.of<ToggleProvider>(context, listen: false);
    final toggleModel = toggleModelData.items;
    final indexUserData = Provider.of<ToggleProvider>(context, listen: false);
    final indexUser = indexUserData.indexUser;
    for (var index = 0; index < toggleModel.length; index += 1) {
      debugPrint('aktueller Index: ' + index.toString());
      selectedUser = List.generate(
        toggleModel.length,
        (index) => index == 0 ? true : false,
      );
      toggleModelData.addIndex(0);
      selectedChildren = List.generate(
        toggleModel.length,
        (index) => UserItem(
          userModel[index].id,
          userModel[index].name,
          userModel[index].image,
          userModel[index].color,
        ),
      );
      //indexUserData.addIndex(0);
    }
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    final indexUserData = Provider.of<ToggleProvider>(context);
    final indexUser = indexUserData.indexUser;
    debugPrint('Inhalt UserIndex ist: ' + indexUser.toString());
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: ToggleButtons(
        constraints: const BoxConstraints(
          minHeight: 40.0,
          maxHeight: 45,
          minWidth: 80.0,
          maxWidth: 85,
        ),
        borderRadius: BorderRadius.circular(30),
        fillColor: Colors.green,
        //disabledBorderColor: Colors.red,
        direction: vertical ? Axis.vertical : Axis.horizontal,
        onPressed: (int index) {
          if (mounted) {
            setState(() {
              selectedUser[index] = !selectedUser[index];
            });
          }
          selectedUser[index] == true
              ? indexUserData.addIndex(index)
              : indexUserData.removeIndex(10);
          debugPrint('selected User ist nun: ' + selectedUser.toString());
          debugPrint('der gecklickte Index ist: ' + index.toString());
        },
        children: selectedChildren,
        isSelected: selectedUser,
      ),
    );
  }
}

Solution

  • I guess this happens because you call notifyListeners() or something like that to update the ui in your initState. The problem here is that the ui is still building inside your initState ... you can try to wrap toggleModelData.addIndex(0);) inside a addPostFrameCallback:

    WidgetsBinding.instance.addPostFrameCallback((_){
    
      toggleModelData.addIndex(0);
    
    });
    

    This will call it after the Frame is rendered