Flutter ListView自定义卡片Text overflow布局溢出问题求解
Flutter ExpansionPanelList头部文本溢出问题修复
问题复现
开发Flutter应用时,在ExpansionPanelList(可折叠列表,和ListView布局逻辑一致)中实现自定义卡片头部,渲染时出现Text横向溢出报错,直接使用Expanded包裹溢出的Text节点会触发布局约束相关异常。
附异常运行效果:
附原始问题代码:
import 'package:flutter/material.dart'; import '../../shared/AppTheme.dart'; class ComandaScreen extends StatefulWidget { const ComandaScreen({Key? key}) : super(key: key); @override State<ComandaScreen> createState() => _ComandaScreenState(); } class _ComandaScreenState extends State<ComandaScreen> { bool expanded = false; int unidades = 0; final List<Map<String, dynamic>> _items = List.generate( 10, (index) => {'id': index, 'Nombre': 'Nuggets $index', 'isExpanded': false, "unidades": 8}); @override Widget build(BuildContext context) { final ButtonStyle flatButtonStyle = TextButton.styleFrom( shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(4.0)), ), ); return Scaffold( appBar: AppBar( title: const Text('Comanda'), backgroundColor: AppTheme.backgroundColor, foregroundColor: AppTheme.primaryTextColor, elevation: 0, ), body: SingleChildScrollView( child: ExpansionPanelList( elevation: 3, expansionCallback: (index, isExpanded) { setState(() { _items[index]['isExpanded'] = !isExpanded; }); }, animationDuration: const Duration(milliseconds: 200), children: _items .map( (item) => ExpansionPanel( canTapOnHeader: true, headerBuilder: (context, isExpanded) { return Container( margin: const EdgeInsets.all(10), child: Row(children: [ const CircleAvatar( child: Text( '1', textAlign: TextAlign.center, )), const SizedBox( width: 10, ), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Nuggets', style: TextStyle(color: Colors.black, fontWeight: FontWeight.w600), ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: const [ Text( 'Unidades: ${7}', style: TextStyle(color: Colors.black), ), Text( 'Pendientes: 400', style: TextStyle(color: Colors.black), ), ], ), const SizedBox( width: 20, ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: const [ Text( 'Precio: 10 €', maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle(color: Colors.black), ), Text( 'Total: 70 €', maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle(color: Colors.black), ), ], ), ], ), ], ), ), ]), ); }, body: ButtonBar( alignment: MainAxisAlignment.spaceAround, buttonHeight: 52.0, buttonMinWidth: 90.0, children: <Widget>[ TextButton( style: flatButtonStyle, onPressed: () { setState(() { item['unidades'] += 1; }); }, child: Column( children: const <Widget>[ Icon( Icons.add, color: AppTheme.grismedio, ), ], ), ), TextButton( style: flatButtonStyle, onPressed: () { setState(() { item['unidades'] -= 1; }); }, child: Column( children: const <Widget>[ Icon( Icons.remove, color: AppTheme.grismedio, ), ], ), ), TextButton( style: flatButtonStyle, onPressed: () {}, child: Column( children: const <Widget>[ Icon( Icons.edit_outlined, color: AppTheme.grismedio, ), ], ), ), TextButton( style: flatButtonStyle, onPressed: () {}, child: Column( children: const <Widget>[ Icon( Icons.delete_outline_outlined, color: AppTheme.grismedio, ), ], ), ), TextButton( style: flatButtonStyle, onPressed: () {}, child: Column( children: const <Widget>[ Icon( Icons.card_giftcard_outlined, color: AppTheme.grismedio, ), ], ), ) ], ), isExpanded: item['isExpanded'], ), ) .toList(), ), ), ); } }
问题根因
- 嵌套Row未做宽度约束:头部外层Row已经用Expanded包裹右侧内容区,但内容区内部嵌套的第二层Row的两个子Column没有拿到明确的横向宽度上限,内部Text渲染时按无界宽度计算,触发横向溢出。
- Expanded使用层级错误:Expanded必须作为Row/Column/Flex等Flex组件的直接子节点使用,直接包裹深层嵌套的Text节点会触发布局约束异常。
修复方案
- 给内层Row的两个并列Column分别添加Expanded包裹,按1:1比例分配剩余横向宽度,让内部Text拿到明确的可用宽度约束。
- 移除内层Row中固定宽度的SizedBox占位,通过调整右侧Column的对齐方式为
CrossAxisAlignment.end实现两端对齐的视觉效果,适配不同屏幕宽度。 - 所有Text组件统一配置
maxLines: 1和overflow: TextOverflow.ellipsis,文本过长时自动显示省略号,避免撑破布局。
修复后核心代码(替换原headerBuilder中内层Row部分即可)
Row( children: [ Expanded( flex: 1, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: const [ Text( 'Unidades: 7', maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle(color: Colors.black), ), Text( 'Pendientes: 400', maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle(color: Colors.black), ), ], ), ), Expanded( flex: 1, child: Column( crossAxisAlignment: CrossAxisAlignment.end, children: const [ Text( 'Precio: 10 €', maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle(color: Colors.black), ), Text( 'Total: 70 €', maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle(color: Colors.black), ), ], ), ), ], )
内容的提问来源于stack exchange,提问作者Jose David
相关产品推荐
相关产品推荐

