Flutter TabBarView标签动态高度无法适配、无固定高度时容器消失求解
问题根源
Flutter自带的TabBarView默认会尝试填充父容器的所有可用高度,当它被放在设置了mainAxisSize: MainAxisSize.min的Column内部时,父组件没有传递固定高度约束,TabBarView就会因为高度计算为0直接消失。你当前手动计算高度的方式兼容性很差,文本换行、数据量变化时都会出现高度不准的问题。
最优解决方案
直接替换TabBarView为IndexedStack配合Tab切换监听,完全满足Wrap动态高度适配需求,不用手动计算高度,也不需要引入第三方依赖:
具体修改步骤
- 定义变量存储当前选中的标签索引,给
_macroTabController添加监听同步索引 - 移除包裹
TabBarView的容器的固定高度、最小高度配置 - 把原有
TabBarView替换为IndexedStack组件,绑定当前索引值
修改后代码示例
// 先在State类里定义变量 int _currentTabIndex = 0; @override void initState() { super.initState(); // 给TabController加监听同步选中索引 _macroTabController.addListener(() { setState(() { _currentTabIndex = _macroTabController.index; }); }); } @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: <Widget>[ Container( margin: const EdgeInsets.only(left: 20), child: TabBar( isScrollable: true, controller: _macroTabController, physics: const NeverScrollableScrollPhysics(), indicatorColor: ColorsConfig.textBlack, labelColor: ColorsConfig.checkMarkBlue, unselectedLabelColor: ColorsConfig.textBlack, labelStyle: TextStyleConfig.getSubtitle2Style( color: ColorsConfig.checkMarkBlue), labelPadding: const EdgeInsets.only(left: 0, right: 20, top: 4), indicatorPadding: const EdgeInsets.only(top: 0, bottom: 8), indicator: const RoundUnderlineTabIndicator( borderSide: BorderSide( width: 3, color: ColorsConfig.checkMarkBlue, )), tabs: const <Widget>[ Tab(text: 'All'), Tab(text: 'Appointment'), Tab(text: 'Guest'), Tab(text: 'Location'), Tab(text: 'Others'), ], ), ), // 移除原来的固定高度、最小高度配置 Container( margin: const EdgeInsets.only(left: 20, right: 12, bottom: 12, top: 18), // 替换TabBarView为IndexedStack child: IndexedStack( index: _currentTabIndex, children: [ Wrap( spacing: 16, runSpacing: 16, children: widget.macroListData.isNotEmpty ? widget.macroListData .map((x) => getPadedMacroText(x, widget.buildLocation, context)) .toList() : [], ), Wrap( spacing: 16, runSpacing: 16, children: widget.macroListData.isNotEmpty ? widget.macroListData .where((element) => element.category == 'Appointment') .map((x) => getPadedMacroText(x, widget.buildLocation, context)) .toList() : [], ), Wrap( spacing: 16, runSpacing: 16, children: widget.macroListData.isNotEmpty ? widget.macroListData .where((element) => element.category == 'Guest') .map((x) => getPadedMacroText(x, widget.buildLocation, context)) .toList() : [], ), Wrap( spacing: 16, runSpacing: 16, children: widget.macroListData.isNotEmpty ? widget.macroListData .where((element) => element.category == 'Location') .map((x) => getPadedMacroText(x, widget.buildLocation, context)) .toList() : [], ), Wrap( spacing: 16, runSpacing: 16, children: widget.macroListData.isNotEmpty ? widget.macroListData .where((element) => element.category == 'Others') .map((x) => getPadedMacroText(x, widget.buildLocation, context)) .toList() : [], ), ], ), ) ], ); }
说明
因为你原本就给TabBar设置了NeverScrollableScrollPhysics,禁止了滑动切换标签,所以用IndexedStack实现的切换效果和原有TabBarView完全一致,同时会自动适配当前显示的Wrap组件的高度,不需要手动计算高度值,适配所有文本长度、数据量的场景。
内容的提问来源于stack exchange,提问作者Vayigandla Bhavya Srikari
相关产品推荐
相关产品推荐

