Search code examples
flutterdartlayoutwidgetstateful

Widget doesn't change, although new state is called


I wanted to have a text, that changes every time one of the filter cards is selected/deselected. I made a global variable (I don't know what the best way to do that is but to me it seemed like it should work) and changed the value of it every time one of the filter cards was tapped. The problem is that the text widget, where the value is supposed to be displayed, doesn't change although the output shows, that the set state function worked. For more info see the pictures and code below.

    class FilterSelectCard extends StatefulWidget {
  FilterSelectCard({
    Key? key,
    required this.filterCategory,
    required this.filterSvg,
    required this.filterIndex,
    required this.appliedFilters,
  }) : super(key: key);
  List<String> filterCategory;
  List<String> filterSvg;
  int filterIndex;
  ValueNotifier<int> appliedFilters;
  @override
  FilterSelectCardState createState() => FilterSelectCardState();
}

class FilterSelectCardState extends State<FilterSelectCard> {
  Color filterColor = primaryColor;
  Color borderColor = secondaryTextColor;
  Color svgColor = secondaryTextColor;
  bool filterStat = false;
  TextStyle textStyle = unTextStyle;
  ValueNotifier<int> appliedFilters = widget.appliedFilters; 

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(
        right: 12,
      ),
      child: GestureDetector(
        onTap: () {
          setState(() {
            if (filterStat == false) {
              filterColor = secondaryTextColor;
              textStyle = selTextStyle;
              borderColor = backgroundColor;
              svgColor = mainTextColor;
              appliedFilters.value += 1;
              print(appliedFilters);
            }
            if (filterStat == true) {
              filterColor = primaryColor;
              textStyle = unTextStyle;
              borderColor = secondaryTextColor;
              svgColor = secondaryTextColor;
              appliedFilters.value -= 1;
              print(appliedFilters);
            }
            if (filterColor == primaryColor) {
              filterStat = false;
            }
            if (filterColor == secondaryTextColor) {
              filterStat = true;
            }
          });
        },

and

Future<dynamic> filterMealsAndWines(BuildContext context) {
    ValueNotifier<int> appliedFilters = ValueNotifier(0);
    return showModalBottomSheet(
      context: context,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(35),
      ),
      builder: (BuildContext context) {
        return Stack(
           children:[Positioned(
                    left: 110,
                    top: 15,
                    child: Container(
                      height: 9,
                      width: 20,
                      decoration: BoxDecoration(
                        color: primaryColor,
                        borderRadius: BorderRadius.circular(
                          20,
                        ),
                      ),
                      child: ValueListenableBuilder(
                        valueListenable: appliedFilters,
                        builder: (context, appliedFilters, _) {
                          return Center(
                            child: Text(
                              appliedFilters.toString(),
                              style: GoogleFonts.poppins(
                                textStyle: const TextStyle(
                                  color: mainTextColor,
                                  fontSize: 6,
                                  fontWeight: FontWeight.w600,
                                ),
                              ),
                            ),
                          );
                        },
                      ),
                    ),
                  ),],

Widget Output


Solution

  • If this widget, is the widget you are trying to update when setState() is called, it doesn't work because it is not in same StatefulWidget as the setState() function in result the widget doesn't rebuild.

    child: Center(
      child: Text(
        appliedFilters.toString(),
        style: GoogleFonts.poppins(
          textStyle: const TextStyle(
            color: mainTextColor,
            fontSize: 6,
            fontWeight: FontWeight.w600,
          ),
        ),
      ),
    ),   
    

    To solve you should read more about state managment in Flutter, but a temporary solution could be using a ValueListenableBuilder

    So you should wrap your Text widget in ValueListenableBuilder and your your value appliedFilters will update the builder whenever it is changed

    Future<dynamic> filterMealsAndWines(BuildContext context){
      ValueNotifier<int> appliedFilters = ValueNotifier(0); 
    
      //Your all previuos code 
    
      ValueListenableBuilder<int>(
        valueListenable: appliedFilters,
        builder: (context, value, _) {
          return Center(
            child: Text(
              appliedFilters.toString(),
              style: GoogleFonts.poppins(
                textStyle: const TextStyle(
                  color: mainTextColor,
                  fontSize: 6,
                  fontWeight: FontWeight.w600,
                ),
              ),
            ),
          );
        }
      ),
    }
    
    class FilterSelectCardState extends State<FilterSelectCard> {
    
      @override
      Widget build(BuildContext context) {
        return Padding(
          padding: const EdgeInsets.only(
            right: 12,
          ),
          child: GestureDetector(
            onTap: () {
              setState(() {
                //HERE YOU UPDATE THE VALUE
                widget.appliedFilters.value += 1;
              });
            },
          ),
    
          //all your other code
    
        );
      }
    }