Flutter中Text组件无法正常显示问题求助
Flutter健身应用标签页名称不显示问题修复
问题说明
开发Flutter健身应用时,已实现支持用户添加/移除的TabView训练页面,但训练名称无法正常显示。
原代码
import 'package:flutter/material.dart'; import 'package:workout_app/Screens/Components/Widgets/footer.dart'; class workout_page extends StatefulWidget { @override _WorkoutPageState createState() => _WorkoutPageState(); } class _WorkoutPageState extends State<workout_page> with TickerProviderStateMixin { late TabController _tabController; List<Map<String, dynamic>> workoutMap = [ { 'name': 'My First Workout', 'exercises': [ { 'name': 'Bicep Curl', 'musclesworked': ['bicep', 'tricep'] }, { 'name': 'Preacher Curl', 'musclesworked': ['bicep', 'tricep'] } ] }, ]; @override void initState() { super.initState(); _tabController = TabController(length: workoutMap.length + 1, vsync: this); } TextEditingController _newTabController = TextEditingController(); void _addTab() { setState(() { String newTabName = _newTabController.text; Map<String, dynamic> newTab = { 'name': newTabName, 'exercises': [], }; workoutMap.add(newTab); _newTabController.clear(); _tabController = TabController( length: workoutMap.length + (workoutMap.length < 4 ? 1 : 0), vsync: this, ); }); } @override Widget build(BuildContext context) { var size = MediaQuery.of(context).size; return Container( decoration: BoxDecoration(color: Color.fromARGB(255, 67, 67, 67)), child: DefaultTabController( length: workoutMap.length + (workoutMap.length < 4 ? 1 : 0), child: Scaffold( backgroundColor: Color.fromRGBO(79, 79, 79, 1), body: Stack( children: [ CustomScrollView( physics: NeverScrollableScrollPhysics(), slivers: [ SliverAppBar( expandedHeight: 30, titleSpacing: 15, pinned: true, elevation: 0, backgroundColor: Color.fromARGB(255, 19, 19, 19), centerTitle: false, bottom: PreferredSize( preferredSize: const Size.fromHeight(0), child: Column(children: [ TabBar( physics: NeverScrollableScrollPhysics(), tabs: [ ...workoutMap.map( (tab) => Tab(text: tab['name'] as String)), if (workoutMap.length < 4) Container( width: 40, height: 40, alignment: Alignment.center, child: IconButton( icon: Icon(Icons.add), onPressed: () { showDialog( context: context, builder: (context) => AlertDialog( title: Text('Add Tab'), content: TextField( controller: _newTabController, decoration: InputDecoration( hintText: 'Enter tab name', ), ), actions: [ TextButton( child: Text('Cancel'), onPressed: () { Navigator.pop(context); }, ), TextButton( child: Text('Add'), onPressed: () { _addTab(); Navigator.pop(context); }, ), ], ), ); }, ), ), ], ), ])), ), SliverToBoxAdapter( child: Container( height: size.height, child: TabBarView( physics: NeverScrollableScrollPhysics(), controller: _tabController, children: [ ...workoutMap.map((tab) => **RIGHT HERE** Text(tab['name'])), if (workoutMap.length < 4) Container(), ], ), ), ) ], ), Footer(tab: 'Workout'), ], ), ), ), ); } }
问题原因及修复方案
核心问题
- 双重TabController冲突:同时使用
DefaultTabController和自定义_tabController,导致TabBar与TabBarView控制器不同步,标签内容无法正确关联。 - 控制器长度计算不一致:
initState和_addTab中计算TabController长度的逻辑不统一,导致标签数量与内容数量不匹配。 - 无效代码残留:
TabBarView子组件中的**RIGHT HERE**标记属于语法错误,阻碍组件渲染。
修复后的代码
import 'package:flutter/material.dart'; import 'package:workout_app/Screens/Components/Widgets/footer.dart'; class WorkoutPage extends StatefulWidget { @override _WorkoutPageState createState() => _WorkoutPageState(); } class _WorkoutPageState extends State<WorkoutPage> with TickerProviderStateMixin { late TabController _tabController; List<Map<String, dynamic>> workoutMap = [ { 'name': 'My First Workout', 'exercises': [ { 'name': 'Bicep Curl', 'musclesworked': ['bicep', 'tricep'] }, { 'name': 'Preacher Curl', 'musclesworked': ['bicep', 'tricep'] } ] }, ]; @override void initState() { super.initState(); // 统一长度计算逻辑 _tabController = TabController( length: workoutMap.length + (workoutMap.length < 4 ? 1 : 0), vsync: this, ); } TextEditingController _newTabController = TextEditingController(); void _addTab() { setState(() { String newTabName = _newTabController.text; if (newTabName.isNotEmpty) { // 避免添加空标签 Map<String, dynamic> newTab = { 'name': newTabName, 'exercises': [], }; workoutMap.add(newTab); _newTabController.clear(); _tabController = TabController( length: workoutMap.length + (workoutMap.length < 4 ? 1 : 0), vsync: this, ); } }); } @override Widget build(BuildContext context) { var size = MediaQuery.of(context).size; return Container( decoration: const BoxDecoration(color: Color.fromARGB(255, 67, 67, 67)), // 移除DefaultTabController,统一使用自定义控制器 child: Scaffold( backgroundColor: const Color.fromRGBO(79, 79, 79, 1), body: Stack( children: [ CustomScrollView( physics: const NeverScrollableScrollPhysics(), slivers: [ SliverAppBar( expandedHeight: 30, titleSpacing: 15, pinned: true, elevation: 0, backgroundColor: const Color.fromARGB(255, 19, 19, 19), centerTitle: false, bottom: PreferredSize( preferredSize: const Size.fromHeight(0), child: Column( children: [ TabBar( controller: _tabController, // 绑定自定义控制器 physics: const NeverScrollableScrollPhysics(), tabs: [ ...workoutMap.map( (tab) => Tab(text: tab['name'] as String), ), if (workoutMap.length < 4) Container( width: 40, height: 40, alignment: Alignment.center, child: IconButton( icon: const Icon(Icons.add), onPressed: () { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Add Tab'), content: TextField( controller: _newTabController, decoration: const InputDecoration( hintText: 'Enter tab name', ), ), actions: [ TextButton( child: const Text('Cancel'), onPressed: () { Navigator.pop(context); }, ), TextButton( child: const Text('Add'), onPressed: () { _addTab(); Navigator.pop(context); }, ), ], ), ); }, ), ), ], ), ], ), ), ), SliverToBoxAdapter( child: Container( height: size.height, child: TabBarView( controller: _tabController, physics: const NeverScrollableScrollPhysics(), children: [ // 移除无效标记,添加文本样式提升可读性 ...workoutMap.map((tab) => Center( child: Text( tab['name'], style: const TextStyle(color: Colors.white, fontSize: 20), ), )), if (workoutMap.length < 4) const SizedBox(), ], ), ), ) ], ), const Footer(tab: 'Workout'), ], ), ), ); } }
关键修改点
- 移除
DefaultTabController,让TabBar与TabBarView绑定同一自定义_tabController,确保标签与内容同步。 - 统一
TabController长度计算逻辑,初始化和添加标签时保持一致。 - 移除
TabBarView中的无效标记,添加文本样式优化显示效果。 - 增加空值判断,避免用户添加空名称标签。
- 修正类名格式(
workout_page改为WorkoutPage,符合Dart命名规范)。
内容的提问来源于stack exchange,提问作者Cidiko Andorem
相关产品推荐
相关产品推荐

