Why parent widget setState disables child widget setState in flutter?

Issue

I try to create a date picker for my flutter app. At first i can choose the day i want and the color of selected day will change. The problem is when i change the month or year in drop down button, I can’t change selected day. Actually all things works and the selected day will be returned, But it’s color won’t change. I’m new to flutter
This is my code.

import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_datepicker/calander_body/day_box.dart';

class CalanderDays extends StatefulWidget {
  final onSelectDays;
  CalanderDays({required this.onSelectDays});
  @override
  State<StatefulWidget> createState() => CalanderDaysState();
}

class CalanderDaysState extends State<CalanderDays> {
  int previousIndex = 0;
  int? monthDrop = 0;
  int? yearDropDowninit = 1940;
  List monthNames = [
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December'
  ];
  String? year, month, day;

  String? fullDate;

  @override
  Widget build(BuildContext context) {
    List<DropdownMenuItem<int>> monthDropDown = List.generate(12, (index) {
      return DropdownMenuItem(
        child: Text(monthNames[index]),
        value: index,
      );
    });
    List<DropdownMenuItem<int>> yearItems =
        List.generate(DateTime.now().year - 1950, (index) {
      return DropdownMenuItem(
        child: Text('${1950 + index}'),
        value: 1950 + index,
      );
    });
    List<DayBox>? days = List.generate(30, (index) {
      return DayBox(
        day: index,
      );
    });

    return Directionality(
        textDirection: TextDirection.rtl,
        child: Flexible(
            flex: 1,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              mainAxisSize: MainAxisSize.min,
              children: [
                Expanded(
                    child: Row(
                  textDirection: TextDirection.rtl,
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: [
                    DropdownButton<int>(
                        iconEnabledColor: Colors.black,
                        value: monthDrop,
                        items: monthDropDown,
                        onChanged: (itemValue) {
                          month = itemValue.toString();
                          setState(() {
                            monthDrop = itemValue;
                          });
                        }),
                    DropdownButton<int>(
                        value: yearDropDowninit,
                        items: yearItems,
                        onChanged: (value) {
                          year = value.toString();
                          setState(() {
                            yearDropDowninit = value;
                          });
                        })
                  ],
                )),
                Flexible(
                    flex: 5,
                    child: GridView.builder(
                        itemCount: 31,
                        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                            crossAxisCount: 7),
                        itemBuilder: (context, i) {
                          return InkWell(
                            onTap: () {
                              int selectedDay = i + 1;
                              day = selectedDay.toString().length == 1
                                  ? day = '0$selectedDay'
                                  : selectedDay.toString();
                              print(day);
                              if (i == previousIndex) {
                                print('previous');
                              } else if (i != previousIndex) {
                                days[i].activate();
                                days[previousIndex].deactivate();
                                previousIndex = i;
                                if (previousIndex == -1) {
                                  print('-1');
                                  return;
                                }
                              }
                            },
                            child: days[i],
                          );
                        }))
              ],
            )));
  }
}

The dayBox widget:

import 'package:flutter/material.dart';

class DayBox extends StatefulWidget {
  final day;

  VoidCallback activate = () {};
  VoidCallback deactivate = () {};
  DayBox({Key? key, required this.day}) : super(key: key);
  @override
  State<StatefulWidget> createState() => DayBoxState();
}

class DayBoxState extends State<DayBox> {
  Color boxColor = Colors.transparent;
  Color textColor = Colors.black;

  @override
  void initState() {
    super.initState();

    widget.activate = active;
    widget.deactivate = deactivate;
  }

  active() {
    Future.delayed(Duration.zero, () {
      setState(() {
        boxColor = Colors.red;
        textColor = Colors.white;
      });
    });
  }

  deactivate() {
    Future.delayed(Duration.zero, () {
      setState(() {
        boxColor = Colors.transparent;
        textColor = Colors.black;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment.center,
      width: 30,
      height: 30,
      decoration: BoxDecoration(
        shape: BoxShape.circle,
        color: boxColor,
      ),
      child: Text(
        '${widget.day + 1}',
        style: TextStyle(
            fontSize: 18,
            color: textColor,
            fontWeight: FontWeight.normal,
            decoration: TextDecoration.none),
      ),
    );
  }
}

I really don’t know what to do.

Solution

Solution ^^ : Make DayBox extend a stateless Widget

class CalanderDays extends StatefulWidget {
 // final onSelectDays;
   CalanderDays();
  @override
   State<StatefulWidget> createState() => CalanderDaysState();
}

 class CalanderDaysState extends State<CalanderDays> {
 int previousIndex = 0;
 int? monthDrop = 0;
 int yearDropDowninit = 1940;

 int _day = 1;

  List monthNames = [
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December'
  ];
 String? year, month, day;

 String? fullDate;

@override
 Widget build(BuildContext context) {
List<DropdownMenuItem<int>> monthDropDown = List.generate(12, (index) {
  return DropdownMenuItem(
    child: Text(monthNames[index]),
    value: index,
  );
});


List<DropdownMenuItem<int>> yearItems =[];


for(int i= yearDropDowninit;i<=DateTime.now().year;i++){
  yearItems.add(DropdownMenuItem(
    child: Text('${i}'),
    value: i,
  ));
}
List.generate(DateTime.now().year - yearDropDowninit, (index) {
  return DropdownMenuItem(
    child: Text('${1950 + index}'),
    value: 1950 + index,
  );
});


return Directionality(
    textDirection: TextDirection.rtl,
    child: Flexible(
        flex: 1,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          mainAxisSize: MainAxisSize.min,
          children: [
            Expanded(
                child: Row(
                  textDirection: TextDirection.rtl,
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: [
                    DropdownButton<int>(
                        iconEnabledColor: Colors.black,
                        value: monthDrop,
                        items: monthDropDown,
                        onChanged: (itemValue) {
                          month = itemValue.toString();
                          setState(() {
                            monthDrop = itemValue;
                          });
                        }),
                    DropdownButton<int>(
                        value: yearDropDowninit,
                        items: yearItems,
                        onChanged: (value) {
                          year = value.toString();
                          setState(() {
                            yearDropDowninit = value!;
                          });
                        })
                  ],
                )),
            Flexible(
                flex: 5,
                child: GridView.builder(
                    itemCount: days.length,
                    gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                        crossAxisCount: 7),
                    itemBuilder: (context, index) {
                      return InkWell(
                        onTap: () {
                            setState(() {
                              _day =index;
                            });
                        },
                        child:  BoxDay(
                          day: index, activated: _day == index ,
                        ) ,
                      );
                    }))
          ],
        )));
}
}




  class BoxDay extends StatelessWidget {
    final day;
    final bool activated;
  const BoxDay({Key? key, required this.activate, this.day}) : super(key: key);

 @override
   Widget build(BuildContext context) {
  return Container(
  alignment: Alignment.center,
  width: 30,
  height: 30,
  decoration: BoxDecoration(
    shape: BoxShape.circle,
    color: activated ? Colors.red : Colors.transparent,
  ),
  child: Text(
    '${day + 1}',
    style: TextStyle(
        fontSize: 18,
        color: activated ? Colors.white : Colors.black,
        fontWeight: FontWeight.normal,
        decoration: TextDecoration.none),
  ),
);
 }
 }

There was an error,

 List<DropdownMenuItem<int>> yearItems =
    List.generate(DateTime.now().year - 1950, (index) {
  return DropdownMenuItem(
    child: Text('${1950 + index}'),
    value: 1950 + index,
  );
  });

to

List<DropdownMenuItem<int>> yearItems =[];


for(int i= yearDropDowninit;i<=DateTime.now().year;i++){
   yearItems.add(DropdownMenuItem(
    child: Text('${i}'),
   value: i,
 ));
 }

Answered By – i.AGUIR

Answer Checked By – Willingham (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *