skip to Main Content

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)
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

2

Answers


  1. Chosen as BEST ANSWER

    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)
                    ],
                  );
                }(),
              ],
            ),
          ),
        );
      }
    }


  2. 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),
                    )),
    }
    }
    
    
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search