使用Get作为状态管理组件时如何正确初始化TabController
解决方案
报错原因
你当前使用的DevWord是StatelessWidget,没有实现TickerProvider接口,因此无法直接将this作为vsync参数传给TabController。且你现有代码已经嵌套了DefaultTabController,手动创建TabController属于冗余逻辑。
方案1:复用现有DefaultTabController(改动最小)
无需额外定义TabController,也不用修改组件类型,直接用框架自带的DefaultTabController实现监听即可:
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'dev_word_controller.dart'; class DevWord extends StatelessWidget { DevWord({Key? key}) : super(key: key); List<String> tabs = ["生词", "已记住", "全部"]; void _handleTabSelection(BuildContext context, TabController tabController) { if (tabController.indexIsChanging) { switch (tabController.index) { case 0: ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: const Text('Page 1 tapped.'), duration: const Duration(milliseconds: 500), )); break; case 1: ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: const Text('Page 2 tapped.'), duration: const Duration(milliseconds: 500), )); break; } } } @override Widget build(BuildContext context) { return GetBuilder<DevWordController>( init: DevWordController(), builder: (controller) { return DefaultTabController( length: tabs.length, // 加Builder拿到DefaultTabController所在层级的context child: Builder( builder: (context) { // 直接获取已有的DefaultTabController实例 final tabController = DefaultTabController.of(context)!; tabController.addListener(() => _handleTabSelection(context, tabController)); return Scaffold( appBar: AppBar( foregroundColor: Colors.red, bottom: PreferredSize( preferredSize: const Size.fromHeight(1), child: Material( color: Colors.green, child: TabBar( indicatorColor: Colors.black, labelColor: Colors.white, unselectedLabelColor: Colors.yellow, tabs: tabs.map((e) => Tab(text: e)).toList(), ), ), ), ), body: SafeArea( child: TabBarView( children: tabs.map((e) { return ListView(children: controller.getCurrentRender); }).toList(), ), ), ); } ), ); } ); } }
方案2:TabController放入GetX Controller(更符合Get状态管理规范)
如果需要单独持有TabController实例做自定义控制,直接把逻辑抽到DevWordController中,用GetX提供的TickerProvider能力即可,完全不需要编写StatefulWidget:
第一步:修改DevWordController
import 'package:flutter/material.dart'; import 'package:get/get.dart'; class DevWordController extends GetxController with GetSingleTickerProviderStateMixin { late TabController tabController; final List<String> tabs = ["生词", "已记住", "全部"]; // 你的其他业务逻辑... List<Widget> get getCurrentRender => []; // 替换为你自己的逻辑 @override void onInit() { super.onInit(); // 直接用当前Controller作为vsync tabController = TabController(length: tabs.length, vsync: this); tabController.addListener(_handleTabSelection); } void _handleTabSelection() { if (tabController.indexIsChanging) { switch (tabController.index) { case 0: // 用Get的SnackBar无需传context Get.showSnackbar(const GetSnackBar( message: 'Page 1 tapped.', duration: Duration(milliseconds: 500), )); break; case 1: Get.showSnackbar(const GetSnackBar( message: 'Page 2 tapped.', duration: Duration(milliseconds: 500), )); break; } } } @override void onClose() { // 销毁TabController避免内存泄漏 tabController.dispose(); super.onClose(); } }
第二步:修改UI层代码
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'dev_word_controller.dart'; class DevWord extends StatelessWidget { DevWord({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return GetBuilder<DevWordController>( init: DevWordController(), builder: (controller) { return Scaffold( appBar: AppBar( foregroundColor: Colors.red, bottom: PreferredSize( preferredSize: const Size.fromHeight(1), child: Material( color: Colors.green, child: TabBar( // 绑定Controller中的tabController controller: controller.tabController, indicatorColor: Colors.black, labelColor: Colors.white, unselectedLabelColor: Colors.yellow, tabs: controller.tabs.map((e) => Tab(text: e)).toList(), ), ), ), ), body: SafeArea( child: TabBarView( // 绑定Controller中的tabController controller: controller.tabController, children: controller.tabs.map((e) { return ListView(children: controller.getCurrentRender); }).toList(), ), ), ); } ); } }
注意事项
- 手动创建的
TabController需要在GetxController的onClose生命周期中调用dispose方法,避免内存泄漏 - 原代码中
Scaffold.of(context)已经被Flutter废弃,建议用ScaffoldMessenger.of(context)替代,或者直接用Get.showSnackbar无需传递context - 不要同时使用
DefaultTabController和自定义TabController,二者选其一即可
内容的提问来源于stack exchange,提问作者Dolphin
相关产品推荐
相关产品推荐

