Search code examples
flutterdartflutter-layout

Flutter TabController late initializer


I am creating an app and I am working on the profile setup and am using a tabcontroller. I have my tabcontroller working to navigate my first 3 screens, but for some reason I get a "late initializtion" error for my last screen. I have a custom button that I use for each screen, and the error gets shown once I add the custom button to my last acrren. Could someone explain to me what I need to do to get it working for my last screen? I've attached my code for the tabcontroller, custom button, and my last screen:

Tabcontroller onboarding model:

class AccountOnboarding extends StatefulWidget {
  const AccountOnboarding({Key? key}) : super(key: key);

  @override
  State<AccountOnboarding> createState() => _AccountOnboardingState();
}

class _AccountOnboardingState extends State<AccountOnboarding> {

    static const List<Tab> tabs = <Tab>[
    Tab(text: 'Name'),
    Tab(text: 'Age and Profile'),
    Tab(text: 'Bio and Interests'),
    Tab(text: 'Selection')
  ];

  @override
  Widget build(BuildContext context) {

    return DefaultTabController(
      length: tabs.length,
       child: Builder(builder: (BuildContext context) {
        final TabController tabController = DefaultTabController.of(context)!;
        tabController.addListener(() {
          if (!tabController.indexIsChanging) {}
        });

    return Scaffold(
      resizeToAvoidBottomInset: false,
      backgroundColor: const Color(0xff31708c),
      appBar: AppBar(
        automaticallyImplyLeading: false,
        backgroundColor: Colors.transparent,
        elevation: 0,
        title: Row(
          children: [
            Expanded(
              child: Image.asset('assets/images/Logo_Strength.png',
              height: 50),
            ),
            Expanded(
              flex: 2,
              child: RichText(
                          text: TextSpan(
                            style: GoogleFonts.montserrat(
                              fontSize: 30),
                              children: <TextSpan> [
                                TextSpan(text: 'Stren', 
                                style: GoogleFonts.montserrat(
                                  color: Colors.white, 
                                  fontWeight: FontWeight.bold, 
                                  letterSpacing: 1,
                                  shadows: [
                                    Shadow(
                                      color: Colors.black.withOpacity(0.7),
                                      offset: const Offset(1.5, 0.0))
                                  ])),
            
                                TextSpan(text: ';', 
                                style: GoogleFonts.montserrat(
                                  color: const Color(0xffef6a7a), fontWeight: FontWeight.bold, 
                                  letterSpacing: 1,
                                  shadows: [
                                    Shadow(
                                      color: Colors.black.withOpacity(0.7),
                                      offset: const Offset(1.5, 0.0))
                                  ])),
            
                                TextSpan(text: 'th', 
                                style: GoogleFonts.montserrat(
                                  color: Colors.white, 
                                  fontWeight: FontWeight.bold, 
                                  letterSpacing: 1,
                                  shadows: [
                                    Shadow(
                                      color: Colors.black.withOpacity(0.7),
                                      offset: const Offset(1.5, 0.0))
                                  ]))
                      ],
                    ),
                  ),
            ),
          ],
        )
    ),
    body: TabBarView(
      // physics: const NeverScrollableScrollPhysics(),
      children: [
        NamePage(tabController: tabController,),
        ageAndPicture(tabController: tabController,),
        bioAndInterests(tabController: tabController,),
        SelectionPage(tabController: tabController,)
      ],
    ),
    );
    
  }));
}}

Custom Button:

class CustomButton extends StatelessWidget {
  final TabController tabController;

  const CustomButton({Key? key,
  required this.tabController}) 
  : super(key: key);

  @override
  Widget build(BuildContext context) {

    return DecoratedBox(
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(50),
        color: Colors.white
      ),
      child: ElevatedButton(
        style: ElevatedButton.styleFrom(
          padding: const EdgeInsets.symmetric(
            vertical: 16),
          elevation: 0,
          primary: Colors.transparent
        ),
        onPressed: () {
          tabController.animateTo(tabController.index + 1);
        },
        child: Container(
          width: double.infinity,
          child: Center(
            child: Text('Continue',
            style: GoogleFonts.montserrat(
              color: const Color.fromARGB(255, 20, 83, 106),
              fontSize: 19,
              fontWeight: FontWeight.w600
            ),),
          ),
        )
      ),
    );
    
  }
}

Last Screen code:

class SelectionPage extends StatefulWidget {
  final TabController tabController;
        
          const SelectionPage({Key? key,
          required this.tabController}) : super(key: key);
        
          @override
        
          _SelectionPageState createState() => _SelectionPageState();
        }
        
        class _SelectionPageState extends State<SelectionPage>{
        
          List <Item>listOfModel = [];
          late TabController tabController;

          @override
          void initState() {
            super.initState();
          }
      
          @override
          Widget build(BuildContext context) {

            String retrieveString;
            final data = ModalRoute.of(context)!.settings;

            if (data.arguments == null) {
              retrieveString = "empty";
            } else {
              retrieveString = data.arguments as String;
            }

            listOfModel.add(Item(title: "Maintaining healthy relationships"));
            listOfModel.add(Item(title: "Stress and anxiety management"));
            listOfModel.add(Item(title: "Maintaing a better work-life balance"));
            listOfModel.add(Item(title: "Personal growth and development"));
            listOfModel.add(Item(title: "Being happier and more content in life"));
            listOfModel.add(Item(title: "Mental and emotional well-being"));
            
            double _height = MediaQuery.of(context).size.height;

            return Scaffold(
              resizeToAvoidBottomInset: false,
              backgroundColor: const Color(0xff31708c),
        
              body: Padding(
                padding: EdgeInsets.only(
                    left: 30,
                    right: 30,
                    top: _height * 0.07,
                    bottom: _height * 0.05),
                child: Column(
                  children: [
                    Column(
                      children: [
                        Column(
                          children: <Widget>[
                            Text('Hello there $retrieveString! What all would you like to focus on?',
                              style: GoogleFonts.montserrat(
                                  color: Colors.white70,
                                  fontSize: 19,
                                  fontWeight: FontWeight.w600
                              ),
                              textAlign: TextAlign.center,),
                              const SizedBox(height: 10),
            Text("You can pick all that apply:",
            style: GoogleFonts.montserrat(
              color: Colors.white70,
              fontSize: 14.5,
              fontWeight: FontWeight.w600
            ),),
                            const SizedBox(height: 15,),
                            GridView.count(
                              primary: true,
                              shrinkWrap: true,
                              padding: const EdgeInsets.all(10),
                              childAspectRatio: 1.15,
                              crossAxisCount: 2,
                              crossAxisSpacing: 25,
                              mainAxisSpacing: 25,
                              children: [
                           gridItem(listOfModel[0],MyFlutterApp.relationships),
                           gridItem(listOfModel[1],MyFlutterApp2.meditate),
                           gridItem(listOfModel[2],MyFlutterApp.balance),
                           gridItem(listOfModel[3],MyFlutterApp2.personal_growth),
                           gridItem(listOfModel[4],MyFlutterApp.happy),
                           gridItem(listOfModel[5],MyFlutterApp3.well_rounded),
                              ],
                            ),
                            const SizedBox(height: 18,),
                          ],
                        ),
                        CustomButton(tabController: tabController)
                      ],
                    ),
                  ],
                ),
              ),
            );
          }

     Widget gridItem(Item item, IconData icon){
        return GestureDetector(
          onTap: () {
            setState(() {
              item.isSelected = !item.isSelected;
            });
          },
          child: Stack(
            children: [Container(
            padding: const EdgeInsets.all(8),
            decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(15),
                border: Border.all(
                    color: const Color.fromARGB(255, 20, 83, 106),
                    width: 2.5),
                color:  item.isSelected ? Color.fromARGB(255, 234, 188, 193) :  Colors.white
            ),
            child: Column(
              children: [
                 Align(alignment: Alignment.topCenter,
                  child: Icon(
                    icon,
                    color: const Color(0xff31708c),
                    size: 45,
                  ),
                ),
                const SizedBox(height: 4,),
                Text(item.title,
                  style: GoogleFonts.montserrat(
                      fontSize: 14,
                      fontWeight: FontWeight.w500,
                      color: const Color(0xff31708c)
                  ),
                  textAlign: TextAlign.center,),
              ],
            ),
          ),
          Positioned(
                    top: 0,
                    right: 0,
                    child: Offstage(
                      offstage: !item.isSelected,
                      child: Container(
                        decoration: BoxDecoration(
                          color: Colors.white,
                          border: Border.all(width: 2.5),
                          shape: BoxShape.circle),
                          child: const Icon(
                            Icons.check,
                            color: Colors.green,
                          ),
                      ),
                    ),
                  )
            ],
          )
        );
      }
 } 
        class Item{
          String title;
          bool isSelected;
        
          Item({required this.title, this.isSelected = false});
        
        }

Solution

  • Remove

    late TabController tabController;
    

    in SelectionPage and change

    CustomButton(tabController: tabController)
    

    in SelectionPage to

    CustomButton(tabController: widget.tabController)