flutterdartdefault-valuedropdownbuttonflutter-dropdownbutton

Flutter : DropdownButtonFormField2 selected item changes to initial value on screen rotation


In my flutter application screen I have a DropdownButtonFormField2 which list various financial years, where after fetching the financial year list I set the current financial year as the initial(default) selected value in the dropdown as code below.The Problem comes when I change the financial year to a different year in dropdown, and it will change to the newly selected financial year in dropdown, but it will reset to the current(initial/default) financial year when I rotate the screen. How to solve this issue?

class AccountSetup extends StatelessWidget {
    FinancialYear selFinancialPeriod = FinancialYear();
    dynamic selFinancialValue;
    List<dynamic>? financialYearList;
    final Company selectedCompany;

    AccountSetup({Key? key, required this.selectedCompany}) : super(key: key);


    @override
    Widget build(BuildContext context) {
        context.read<MyAccountBloc>().add(FetchFinancialYearList(selectedCompany.id!));
        return BlocBuilder<MyAccountBloc, MyAccountState>(
            builder: (context, state) {
            if(state is FinancialYearList) {
                financialYearList = state.list;
                if(financialYearList != null) {
                    for(dynamic itemFY in financialYearList!) {
                        if(DateTime.now().isBetween(yMdFormat.parse(itemFY['startDate']), yMdFormat.parse(itemFY['endDate']))) {
                            selFinancialPeriod = FinancialYear.fromJson(itemFY);
                            selFinancialValue = itemFY;
                            break;
                        }
                    }
                }
                getFinancialPeriodDropDown(context);
            } else if(state is AccountTabChanged) {
                ....
            } else if(state is UpdateDropDown) {
                selFinancialValue = state.selValue;
                selFinancialPeriod = FinancialYear.fromJson(selFinancialValue);
                getFinancialPeriodDropDown(context);
            }
            return MaterialApp(
                home: Scaffold(
                body: SafeArea(
                    child: Stack(
                        children: [
                            Container(
                                child: Column(
                                    children: [
                                        SizedBox(height: 3,),
                                        getFinancialPeriodDropDown(context),
                                        SizedBox(height: 3,),
                                        DefaultTabController(
                                            length: 2, // length of tabs
                                            initialIndex: 0,
                                            child: Builder(
                                                builder: (context) {
                                                    tabController = DefaultTabController.of(context);
                                                    tabController?.addListener(() {
                                                        selTab = tabController?.index;
                                                        context.read<MyAccountBloc>().add(ChangeTabEvent(tabIndex: tabController?.index));
                                                    });
                                                    return Column(
                                                        children: <Widget>[
                                                            ....
                                                        ],
                                                    );
                                                },
                                            ),
                                        ),
                                    ],
                                ),
                            ),
                            Positioned(
                                bottom: 0,
                                left: 30,
                                right: 30,
                                child: getTabButtons(context),
                            ),
                        ],
                    )
                ),
                ),
            );
            }
        );
    }

    getFinancialPeriodDropDown(BuildContext context) {
        if(financialYearList == null) {
            return SizedBox();
        }
        return setAcademicDropDown(context);
    }

    setFinancialPeriodDropDown(BuildContext context) {
        return SizedBox(
            height: 45,
            child: DropdownButtonFormField2<dynamic>(
                isExpanded: true,
                hint: const Text('Select Financial Year',style: TextStyle(fontSize: 14),),
                value: selFinancialValue,
                items: financialYearList!.map((item) => DropdownMenuItem<dynamic>(
                    value: item,
                    child: Text('${dMyFormat.format(yMdFormat.parse(item['startDate']))} :: ${dMyFormat.format(yMdFormat.parse(item['endDate']))}',
                        style: const TextStyle(fontSize: 14,),
                    ),)).toList(),
                validator: (value) {
                    if (value == null) {
                        return 'Please select $txtAcaPer.';
                    }
                },
                onChanged: (value) {
                    context.read<MyAccountBloc>().add(UpdateDropDownEvent(selValue: value));
                },
                onSaved: (value) {},
            ),
        );
    }

}

One more thing I need to know is, how can i set the initial(default) value to nothing (ie, like 'Select Financial Year') when I open the page instead of the current financial year??

Edit :

I saw same kind of problem on the below question also

flutter dropdownbutton won't keep answer after scrolling


Solution

  • If you really don't want to lose the selection on orientation change then make the AccountSetup widget as StatefulWidget.

    Then your code will be as following

    class AccountSetup extends StatefulWidget {
      final Company selectedCompany;
    
      AccountSetup({Key? key, required this.selectedCompany}) : super(key: key);
    
      @override
      State<AccountSetup> createState() => _AccountSetupState();
    }
    
    class _AccountSetupState extends State<AccountSetup> {
      FinancialYear selFinancialPeriod = FinancialYear();
      dynamic selFinancialValue;
      List<dynamic>? financialYearList;
    
      @override
      Widget build(BuildContext context) {
        context.read<MyAccountBloc>().add(FetchFinancialYearList(widget.selectedCompany.id!));
        return BlocBuilder<MyAccountBloc, MyAccountState>(
            builder: (context, state) {
              if(state is FinancialYearList) {
                financialYearList = state.list;
                if(financialYearList != null) {
                  for(dynamic itemFY in financialYearList!) {
                    if(DateTime.now().isBetween(yMdFormat.parse(itemFY['startDate']), yMdFormat.parse(itemFY['endDate']))) {
                      selFinancialPeriod = FinancialYear.fromJson(itemFY);
                      selFinancialValue = itemFY;
                      break;
                    }
                  }
                }
                getFinancialPeriodDropDown(context);
              } else if(state is AccountTabChanged) {
                selTab = state.tabIndex;
                //tabController!.index = selTab!;
                getTabButtons(context);
              } else if(state is UpdateDropDown) {
                selFinancialValue = state.selValue;
                selFinancialPeriod = FinancialYear.fromJson(selFinancialValue);
                getFinancialPeriodDropDown(context);
              }
              return MaterialApp(
                scrollBehavior: MyCustomScrollBehavior(),
                title: ....,
                debugShowCheckedModeBanner: false,
                theme: ThemeData(
                  colorScheme: ColorScheme.fromSwatch().copyWith(
                    primary: primaryColor,
                  ),),
                home: Scaffold(
                  resizeToAvoidBottomInset: false,
                  appBar: sizedAppBar,
                  body: SafeArea(
                      child: Stack(
                        children: [
                          Container(
                            child: Column(
                              children: [
                                SizedBox(height: 3,),
                                getFinancialPeriodDropDown(context),
                                SizedBox(height: 3,),
                                DefaultTabController(
                                  length: 2, // length of tabs
                                  initialIndex: 0,
                                  child: Builder(
                                    builder: (context) {
                                      tabController = DefaultTabController.of(context);
                                      tabController?.addListener(() {
                                        selTab = tabController?.index;
                                        context.read<MyAccountBloc>().add(ChangeTabEvent(tabIndex: tabController?.index));
                                      });
                                      return Column(
                                        children: <Widget>[
                                          Container(
                                            child: TabBar(
                                              controller: tabController,
                                              labelColor: textWhite1,
                                              unselectedLabelColor: Colors.black,
                                              indicatorWeight: 2,
                                              isScrollable: true,
                                              indicatorSize: TabBarIndicatorSize.tab,
                                              indicatorColor: selColor1,
                                              indicatorPadding: EdgeInsets.only(left: 2.0, right: 2.0,bottom: 3.0),
                                              indicator: BoxDecoration(
                                                borderRadius: BorderRadius.circular(5),color: highlightGrey10,shape: BoxShape.rectangle,
                                              ),
                                              labelPadding: EdgeInsets.symmetric (horizontal: 1),
                                              tabs: [
                                                Container(
                                                  width: mainTabWidth,
                                                  height: mainTabHeight,
                                                  decoration: BoxDecoration(color: tab1Color,border: Border.all(color: border1Color,width: 2,style: BorderStyle.solid),borderRadius: BorderRadius.circular(5)),
                                                  child: Tab(child:Text(tabAccSt1,textAlign: TextAlign.center,style: TextStyle(fontSize: fontSize,fontWeight: FontWeight.bold,),),),
                                                ),
                                                Container(
                                                  width: mainTabWidth,
                                                  height: mainTabHeight,
                                                  decoration: BoxDecoration(color: tab2Color,border: Border.all(color: border1Color,width: 2,style: BorderStyle.solid),borderRadius: BorderRadius.circular(5)),
                                                  child: Tab(child:Text(tabAccSt2,textAlign: TextAlign.center,style: TextStyle(fontSize: fontSize,fontWeight: FontWeight.bold,),),),
                                                ),
                                              ],
                                            ),
                                          ),
                                          Container(
                                            height: 400, //height of TabBarView
                                            decoration: BoxDecoration(
                                                border: Border(top: BorderSide(color: Colors.grey, width: 0.5))
                                            ),
                                            child: TabBarView(
                                              controller: tabController,
                                              children: <Widget>[
                                                Container(
                                                  child: Column(
                                                    children: [
                                                      getCompanySites(),
                                                    ],
                                                  ),
                                                ),
                                                Container(
                                                  child: Center(
                                                    child: Text('Display Tab 2', style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold)),
                                                  ),
                                                ),
                                              ],
                                            ),
                                          ),
                                        ],
                                      );
                                    },
                                  ),
                                ),
                              ],
                            ),
                          ),
                          Positioned(
                            bottom: 0,
                            left: 30,
                            right: 30,
                            child: getTabButtons(context),
                          ),
                        ],
                      )
                  ),
                ),
              );
            }
        );
      }
    
      getFinancialPeriodDropDown(BuildContext context) {
        if(financialYearList == null) {
          return SizedBox();
        }
        return setAcademicDropDown(context);
      }
    
      setFinancialPeriodDropDown(BuildContext context) {
        return SizedBox(
          height: 45,
          child: DropdownButtonFormField2<dynamic>(
            isExpanded: true,
            hint: const Text('Select Financial Year',style: TextStyle(fontSize: 14),),
            value: selFinancialValue,
            icon: const Icon(Icons.arrow_drop_down,color: Colors.black45,),
            iconSize: 30,
            buttonHeight: 60,
            buttonPadding: const EdgeInsets.only(left: 20, right: 10),
            dropdownDecoration: BoxDecoration(borderRadius: BorderRadius.circular(15),),
            items: financialYearList!.map((item) => DropdownMenuItem<dynamic>(
              value: item,
              child: Text('${dMyFormat.format(yMdFormat.parse(item['startDate']))} :: ${dMyFormat.format(yMdFormat.parse(item['endDate']))}',
                style: const TextStyle(fontSize: 14,),
              ),)).toList(),
            validator: (value) {
              if (value == null) {
                return 'Please select $txtAcaPer.';
              }
            },
            onChanged: (value) {
              context.read<MyAccountBloc>().add(UpdateDropDownEvent(selValue: value));
            },
            onSaved: (value) {},
          ),
        );
      }
    }
    

    If you not seeing any changes on UI then, you have to call setState method to refresh the UI.