Home > Mobile >  How do i correctly initialise a variable from a stateful widget to another widget in flutter and mai
How do i correctly initialise a variable from a stateful widget to another widget in flutter and mai

Time:01-09

I have two widgets

  • JobsHeaderWidget
  • JobsView

JobsHeaderWidget is a stateful widget where i code all the logic and initialise int current = 0; in the state. In this same file, i have another class named CategoriesBuilder where i use switch cases to make sure at each switch case a different container is returned. ( a switch case for each tab )

This switch cases is now responsible for switching containers depending on the tab bar selected as seen in this image:

Tab bars

I will also drop the code snippet of the JobsHeaderWidget for better clarifications.

The problem is - when i use this CategoriesBuilder in same widget as the 'JobsHeaderWidget' it works. But i don't want to use it in same widget cos of the logic of my design. I want to be able to use this builder in JobsView widget which is another dart file and it doesn't work maybe because of wrong approach.

  • I tried converting the JobsView to a stateful widget and initialising 'int current = 0;' but it doesn't work.

  • I also tried making int current = 0; global var, it worked but the state doesn't change when i select individual tab bars. ( I mean my switch cases don't seem to work ).

  • I have gone round stackoverflow for answers before asking this but can't find a solution.

Snippets of each widgets below.

JobsHeaderWidget

class JobsHeaderWidget extends StatefulWidget {
  const JobsHeaderWidget({
    Key key,
  }) : super(key: key);

  @override
  State<JobsHeaderWidget> createState() => _JobsHeaderWidgetState();
}

class _JobsHeaderWidgetState extends State<JobsHeaderWidget> {
  List<String> items = [
    "All",
    "Critical",
    "Open",
    "Closed",
    "Overdue",
  ];
  ValueChanged<int> onChange;
  int current = 0;

  List<DropdownMenuItem<String>> get dropdownItems {
    List<DropdownMenuItem<String>> menuItems = [
      DropdownMenuItem(
          child: Text(
            "Today",
          ),
          value: "Today"),
    ];
    return menuItems;
  }

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(left: 15.0, right: 15.0),
      child: SingleChildScrollView(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.end,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Jobs',
              style: GoogleFonts.poppins(
                  color: Colors.black,
                  fontSize: 18,
                  fontWeight: FontWeight.w600),
            ),
            Row(
              children: [
                Text(
                  'View Insights  ',
                  style: GoogleFonts.poppins(
                      color: Color(0xff3498DB),
                      fontSize: 12,
                      fontWeight: FontWeight.w500),
                ),
                Icon(
                  Icons.arrow_forward_ios,
                  color: Color(0xff3498DB),
                  size: 12,
                ),
              ],
            ),
            SizedBox(
              height: 10,
            ),
            filterJobs(),
          ],
        ),
      ),
    );
  }

  Widget filterJobs() {
    String selectedValue = "Today";

    return Column(
      children: [
        Container(
          constraints: const BoxConstraints(maxWidth: 600, maxHeight: 100),
          width: double.infinity,
          child: IntrinsicWidth(
            child: FittedBox(
              fit: BoxFit.fitWidth,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: [
                  for (int i = 0; i < items.length; i  ) ...[
                    GestureDetector(
                      onTap: () {
                        setState(() {
                          current = i;
                        });
                      },
                      child: AnimatedContainer(
                        height: 40,
                        duration: const Duration(milliseconds: 300),
                        margin: const EdgeInsets.all(5),
                        padding: const EdgeInsets.only(
                            left: 14.0, right: 14.0, top: 4, bottom: 4),
                        decoration: BoxDecoration(
                          color: current == i
                              ? const Color(0xff34495E)
                              : const Color(0xffF5F5F5),
                          borderRadius: BorderRadius.circular(50),
                        ),
                        child: Center(
                          child: Text(
                            items[i],
                            style: GoogleFonts.poppins(
                                fontSize: 15,
                                fontWeight: FontWeight.w500,
                                color:
                                    current == i ? Colors.white : Colors.grey),
                          ),
                        ),
                      ),
                    ),
                  ]
                ],
              ),
            ),
          ),
        ),
        Divider(
          color: Color(0xff34495E).withOpacity(0.2),
        ),
        Row(
          children: [
            Text(
              'All Jobs',
              style:
                  GoogleFonts.poppins(fontSize: 9, fontWeight: FontWeight.w400),
            ),
            SizedBox(
              width: 5,
            ),
            Text(
              ' * This Week',
              style:
                  GoogleFonts.poppins(fontSize: 9, fontWeight: FontWeight.w400),
            ),
          ],
        ),
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Text(
              '25',
              style: GoogleFonts.poppins(
                  fontSize: 20, fontWeight: FontWeight.w600),
            ),
            Container(
              height: 30,
              decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(2),
                  color: Color(0xffF4F4F4)),
              child: Padding(
                padding: const EdgeInsets.only(
                  left: 8.0,
                ),
                child: Row(
                  children: [
                    Container(
                      decoration: BoxDecoration(
                          color: Color(0xff34495E),
                          borderRadius: BorderRadius.circular(2)),
                      child: Icon(
                        Icons.tune,
                        size: 15,
                        color: Colors.white,
                      ),
                    ),
                    SizedBox(
                      width: 5,
                    ),
                    DropdownMenuItem(
                      child: DropdownButtonHideUnderline(
                        child: Container(
                          child: DropdownButton(
                            isDense: true,
                            style: GoogleFonts.poppins(
                              fontSize: 10,
                              fontWeight: FontWeight.w500,
                              color: Color(0xff34495E),
                            ),
                            onChanged: (value) {},
                            items: dropdownItems,
                            value: selectedValue,
                          ),
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
        //If i uncomment this line and use the category builder here, it works fine!  CategoriesBuilder(current: current)
      ],
    );
  }
}

class CategoriesBuilder extends StatelessWidget {
  const CategoriesBuilder({
    Key key,
    @required this.current,
  }) : super(key: key);

  final int current;

  @override
  Widget build(BuildContext context) {
    return Builder(
      builder: (context) {
        switch (current) {
          case 0:
            return AllJobsListView();
          case 1:
            return CriticalJobsListView();
          case 2:
            return OpenJobsListView();
          case 3:
            return ClosedJobsListView();
          case 4:
            return OverdueJobsListView();
          default:
            return SizedBox.shrink();
        }
      },
    );
  }
}

JobsView

class JobsView extends StatefulWidget {
  const JobsView({
    Key key,
  }) : super(key: key);
  @override
  State<JobsView> createState() => _JobsViewState();
}

class _JobsViewState extends State<JobsView> {
  int current = 0;
  @override
  Widget build(BuildContext context) {
    final controller = Get.put(EServicesController());
    return Scaffold(
      // floatingActionButton: new FloatingActionButton(
      //   child: new Icon(Icons.add, size: 32, color: Get.theme.primaryColor),
      //   onPressed: () => {Get.offAndToNamed(Routes.E_SERVICE_FORM)},
      //   backgroundColor: Get.theme.colorScheme.secondary,
      // ),
      floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
      body: RefreshIndicator(
        onRefresh: () async {
          Get.find<LaravelApiClient>().forceRefresh();
          controller.refreshEServices(showMessage: true);
          Get.find<LaravelApiClient>().unForceRefresh();
        },
        child: CustomScrollView(
          controller: controller.scrollController,
          physics: AlwaysScrollableScrollPhysics(),
          shrinkWrap: false,
          slivers: <Widget>[
            SliverAppBar(
                backgroundColor: Color(0xffFFFFFF),
                expandedHeight: MediaQuery.of(context).size.height * 0.4,
                elevation: 0.5,
                primary: true,
                pinned: false,
                floating: false,
                //iconTheme: IconThemeData(color: Get.theme.primaryColor),
                // title: Text(
                //   "Jobs".tr,
                //   style: Get.textTheme.headline6
                //       .merge(TextStyle(color: Get.theme.primaryColor)),
                // ),
                centerTitle: false,
                automaticallyImplyLeading: false,
                // leading: new IconButton(
                //   icon: new Icon(Icons.arrow_back_ios,
                //       color: Get.theme.primaryColor),
                //   onPressed: () => {Get.back()},
                // ),
                actions: [
                  SearchButtonWidget(),
                ],
                //bottom: HomeSearchBarWidget(),
                flexibleSpace: FlexibleSpaceBar(
                  collapseMode: CollapseMode.parallax,
                  title: JobsHeaderWidget(),
                )),
            SliverToBoxAdapter(
              child: Wrap(
                children: [
                  //ServicesListWidget(),
                  // The state doesnt change here for some reasosns CategoriesBuilder(current: current)
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

CodePudding user response:

Try this: keep your 'int current' within _JobsViewState as you have in your code.

When you call your JobsHeaderWidget , pass the function it will use to update the the value of the current variable; and rebuild the state from here.

Something like this:


class JobsHeaderWidget extends StatefulWidget {
  final Function changeCurrentValue(int newValue);
  const JobsHeaderWidget({
    this.changeCurrentValue,
    Key key,
  }) : super(key: key);

  @override
  State<JobsHeaderWidget> createState() => _JobsHeaderWidgetState();
}

class _JobsHeaderWidgetState extends State<JobsHeaderWidget> {

@override
  Widget build(BuildContext context) {

    // Somewhere inside build, instead calling setState()
    // call the function you passed to the widget
   
      GestureDetector(
           onTap: () {
                 changeCurrentValue(i);
           },
      )
  }
}


class _JobsViewState extends State<JobsView> {
  int current = 0;

  void changeCurrentValue(int newValue) {
       setState(() {
           current = newValue;
       });
  }

@override
  Widget build(BuildContext context) {

  //somewhere inside build
 flexibleSpace: FlexibleSpaceBar(
                  collapseMode: CollapseMode.parallax,
                  title: JobsHeaderWidget(changeCurrentValue: changeCurrentValue),
                )),
}
}



CodePudding user response:

After hours and even sleeping overnight on this question i came up with a work-around that works. (minor refactoring)

This was my approach :

  • Convert my JobsView widget to a stateful widget and put all my controllers in place.
  • Copied all my variables from JobHeaderWidget and put it in the state of my JobsView widget.
  • Instead of returning a widget in the title of my sliver app as thus :

flexibleSpace: FlexibleSpaceBar( collapseMode: CollapseMode.parallax, title: JobsHeaderWidget(), )),

I copied all of my code from the widget tree from JobsHeaderWidget and put converted to a method and replaced it in my title.

  • My builder CategoryBuilder was put in a separate then imported as i used it in my SliverAppAdapter .

  • Of cos i got rid of the unnecessary dart file JobsHeaderWidget.

FULL CODE BELOW

class JobsView extends StatefulWidget {
  @override
  State<JobsView> createState() => _JobsViewState();
}

class _JobsViewState extends State<JobsView> {
  List<String> items = [
    "All",
    "Critical",
    "Open",
    "Closed",
    "Overdue",
  ];
  int current = 0;

  List<DropdownMenuItem<String>> get dropdownItems {
    List<DropdownMenuItem<String>> menuItems = [
      DropdownMenuItem(
          child: Text(
            "Today",
          ),
          value: "Today"),
    ];
    return menuItems;
  }

  @override
  Widget build(BuildContext context) {
    final controller = Get.put(EServicesController());
    return Scaffold(
      // floatingActionButton: new FloatingActionButton(
      //   child: new Icon(Icons.add, size: 32, color: Get.theme.primaryColor),
      //   onPressed: () => {Get.offAndToNamed(Routes.E_SERVICE_FORM)},
      //   backgroundColor: Get.theme.colorScheme.secondary,
      // ),
      floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
      body: RefreshIndicator(
        onRefresh: () async {
          Get.find<LaravelApiClient>().forceRefresh();
          controller.refreshEServices(showMessage: true);
          Get.find<LaravelApiClient>().unForceRefresh();
        },
        child: CustomScrollView(
          controller: controller.scrollController,
          physics: AlwaysScrollableScrollPhysics(),
          shrinkWrap: false,
          slivers: <Widget>[
            SliverAppBar(
                backgroundColor: Color(0xffFFFFFF),
                expandedHeight: MediaQuery.of(context).size.height * 0.4,
                elevation: 0.5,
                primary: true,
                pinned: false,
                floating: false,
                //iconTheme: IconThemeData(color: Get.theme.primaryColor),
                // title: Text(
                //   "Jobs".tr,
                //   style: Get.textTheme.headline6
                //       .merge(TextStyle(color: Get.theme.primaryColor)),
                // ),
                centerTitle: false,
                automaticallyImplyLeading: false,
                // leading: new IconButton(
                //   icon: new Icon(Icons.arrow_back_ios,
                //       color: Get.theme.primaryColor),
                //   onPressed: () => {Get.back()},
                // ),
                actions: [
                  SearchButtonWidget(),
                ],
                //bottom: HomeSearchBarWidget(),
                flexibleSpace: FlexibleSpaceBar(
                  collapseMode: CollapseMode.parallax,
                  title: mainHeader(),
                )),
            SliverToBoxAdapter(
              child: Wrap(
                children: [
                  //ServicesListWidget(),
                  CategoriesBuilder(current: current)
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

  Padding mainHeader() {
    return Padding(
      padding: const EdgeInsets.only(left: 15.0, right: 15.0),
      child: SingleChildScrollView(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.end,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Jobs',
              style: GoogleFonts.poppins(
                  color: Colors.black,
                  fontSize: 18,
                  fontWeight: FontWeight.w600),
            ),
            Row(
              children: [
                Text(
                  'View Insights  ',
                  style: GoogleFonts.poppins(
                      color: Color(0xff3498DB),
                      fontSize: 12,
                      fontWeight: FontWeight.w500),
                ),
                Icon(
                  Icons.arrow_forward_ios,
                  color: Color(0xff3498DB),
                  size: 12,
                ),
              ],
            ),
            SizedBox(
              height: 10,
            ),
            () {
              String selectedValue = "Today";

              return Column(
                children: [
                  Container(
                    constraints:
                        const BoxConstraints(maxWidth: 600, maxHeight: 100),
                    width: double.infinity,
                    child: IntrinsicWidth(
                      child: FittedBox(
                        fit: BoxFit.fitWidth,
                        child: Row(
                          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                          children: [
                            for (int i = 0; i < items.length; i  ) ...[
                              GestureDetector(
                                onTap: () {
                                  setState(() {
                                    current = i;
                                  });
                                },
                                child: AnimatedContainer(
                                  height: 40,
                                  duration: const Duration(milliseconds: 300),
                                  margin: const EdgeInsets.all(5),
                                  padding: const EdgeInsets.only(
                                      left: 14.0,
                                      right: 14.0,
                                      top: 4,
                                      bottom: 4),
                                  decoration: BoxDecoration(
                                    color: current == i
                                        ? const Color(0xff34495E)
                                        : const Color(0xffF5F5F5),
                                    borderRadius: BorderRadius.circular(50),
                                  ),
                                  child: Center(
                                    child: Text(
                                      items[i],
                                      style: GoogleFonts.poppins(
                                          fontSize: 15,
                                          fontWeight: FontWeight.w500,
                                          color: current == i
                                              ? Colors.white
                                              : Colors.grey),
                                    ),
                                  ),
                                ),
                              ),
                            ]
                          ],
                        ),
                      ),
                    ),
                  ),
                  Divider(
                    color: Color(0xff34495E).withOpacity(0.2),
                  ),
                  Row(
                    children: [
                      Text(
                        'All Jobs',
                        style: GoogleFonts.poppins(
                            fontSize: 9, fontWeight: FontWeight.w400),
                      ),
                      SizedBox(
                        width: 5,
                      ),
                      Text(
                        ' * This Week',
                        style: GoogleFonts.poppins(
                            fontSize: 9, fontWeight: FontWeight.w400),
                      ),
                    ],
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Text(
                        '25',
                        style: GoogleFonts.poppins(
                            fontSize: 20, fontWeight: FontWeight.w600),
                      ),
                      Container(
                        height: 30,
                        decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(2),
                            color: Color(0xffF4F4F4)),
                        child: Padding(
                          padding: const EdgeInsets.only(
                            left: 8.0,
                          ),
                          child: Row(
                            children: [
                              Container(
                                decoration: BoxDecoration(
                                    color: Color(0xff34495E),
                                    borderRadius: BorderRadius.circular(2)),
                                child: Icon(
                                  Icons.tune,
                                  size: 15,
                                  color: Colors.white,
                                ),
                              ),
                              SizedBox(
                                width: 5,
                              ),
                              DropdownMenuItem(
                                child: DropdownButtonHideUnderline(
                                  child: Container(
                                    child: DropdownButton(
                                      isDense: true,
                                      style: GoogleFonts.poppins(
                                        fontSize: 10,
                                        fontWeight: FontWeight.w500,
                                        color: Color(0xff34495E),
                                      ),
                                      onChanged: (value) {},
                                      items: dropdownItems,
                                      value: selectedValue,
                                    ),
                                  ),
                                ),
                              ),
                            ],
                          ),
                        ),
                      ),
                    ],
                  ),
                  //CategoriesBuilder(current: current)
                ],
              );
            }(),
          ],
        ),
      ),
    );
  }
}

  • Related