Flutter TabController late初始化错误:最后一页加自定义按钮后报错
问题分析与解决方案
问题原因
- 未初始化的late变量:在
_SelectionPageState中声明了late TabController tabController;,但从未对其赋值。虽然SelectionPage已经通过构造函数接收了父组件传递的tabController,但State类内部的这个同名变量没有关联到传入的实例,导致CustomButton使用它时触发"late initialization"错误。 - 重复添加数据:在
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
相关产品推荐
相关产品推荐

