You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter TabController late初始化错误:最后一页加自定义按钮后报错

问题分析与解决方案

问题原因

  1. 未初始化的late变量:在_SelectionPageState中声明了late TabController tabController;,但从未对其赋值。虽然SelectionPage已经通过构造函数接收了父组件传递的tabController,但State类内部的这个同名变量没有关联到传入的实例,导致CustomButton使用它时触发"late initialization"错误。
  2. 重复添加数据:在build方法中每次都会执行listOfModel.add(...),导致页面重建时列表会重复添加相同的Item,引发数据冗余。

解决方案

方案1:直接使用父组件传递的tabController(推荐)

删除State类中声明的late TabController tabController;,在使用时直接通过widget.tabController访问父组件传入的实例,同时将数据初始化逻辑移到initState避免重复添加:

class _SelectionPageState extends State<SelectionPage>{
  List <Item>listOfModel = [];

  @override
  void initState() {
    super.initState();
    // 初始化数据,仅执行一次
    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"));
  }

  @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;
    }
    
    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,),
                  ],
                ),
                // 使用widget.tabController访问父组件传入的实例
                CustomButton(tabController: widget.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,
                        ),
                    ),
                  ),
                )
        ],
      )
    );
  }
}

方案2:初始化State内的tabController

如果需要在State类中保留单独的tabController变量,在initState中对其赋值:

class _SelectionPageState extends State<SelectionPage>{
  List <Item>listOfModel = [];
  late TabController tabController;

  @override
  void initState() {
    super.initState();
    // 初始化late变量,关联父组件传入的实例
    tabController = widget.tabController;
    // 初始化数据
    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"));
  }

  @override
  Widget build(BuildContext context) {
    // 其余代码不变
    CustomButton(tabController: tabController)
    // 其余代码不变
  }
}

额外优化点

最后一页是流程的终点,点击按钮时需要避免索引越界,可以修改CustomButton的onPressed逻辑:

onPressed: () {
  if (tabController.index < tabController.length - 1) {
    tabController.animateTo(tabController.index + 1);
  } else {
    // 处理最后一步逻辑,比如跳转到首页
    // Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => HomePage()));
  }
},

内容的提问来源于stack exchange,提问作者Ta-Ty

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 15:50:28