如何实现Row中两个Flexible组件的自适应弹性布局?
实现动态分配宽度的Row布局
要满足你提出的三种布局场景,单纯依赖Flexible/Expanded无法实现动态调整逻辑,需要结合文本宽度预计算和条件布局来处理。以下是具体实现方案:
核心思路
- 预计算两个文本在无约束下的原始宽度
- 获取Row的可用总宽度,对比文本宽度与总宽度的一半:
- 若两个文本宽度之和 ≤ 总宽度:用
MainAxisAlignment.spaceBetween让它们分居左右 - 若只有一个文本宽度 > 总宽度的一半:让该文本优先占用所需空间,另一个文本占剩余宽度
- 若两个文本宽度都 > 总宽度的一半:用
Flexible按1:1比例平分宽度
- 若两个文本宽度之和 ≤ 总宽度:用
完整代码实现
import 'package:flutter/material.dart'; class DynamicTextRow extends StatefulWidget { final String leftText; final String rightText; final TextStyle? textStyle; const DynamicTextRow({ super.key, required this.leftText, required this.rightText, this.textStyle, }); @override State<DynamicTextRow> createState() => _DynamicTextRowState(); } class _DynamicTextRowState extends State<DynamicTextRow> { double _leftTextWidth = 0; double _rightTextWidth = 0; @override void initState() { super.initState(); _calculateTextWidths(); } @override void didUpdateWidget(covariant DynamicTextRow oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.leftText != widget.leftText || oldWidget.rightText != widget.rightText || oldWidget.textStyle != widget.textStyle) { _calculateTextWidths(); } } void _calculateTextWidths() { final textStyle = widget.textStyle ?? const TextStyle(); final leftPainter = TextPainter( text: TextSpan(text: widget.leftText, style: textStyle), textDirection: TextDirection.ltr, )..layout(); final rightPainter = TextPainter( text: TextSpan(text: widget.rightText, style: textStyle), textDirection: TextDirection.ltr, )..layout(); setState(() { _leftTextWidth = leftPainter.width; _rightTextWidth = rightPainter.width; }); } @override Widget build(BuildContext context) { return LayoutBuilder( builder: (context, constraints) { final totalWidth = constraints.maxWidth; final halfWidth = totalWidth / 2; // 情况1:两个文本都短,总宽度不超过可用空间 if (_leftTextWidth + _rightTextWidth <= totalWidth) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(widget.leftText, style: widget.textStyle), Text(widget.rightText, style: widget.textStyle), ], ); } // 情况2:其中一个文本较长,但未占用另一个的空间 if (_leftTextWidth <= halfWidth && _rightTextWidth > halfWidth) { return Row( children: [ Text(widget.leftText, style: widget.textStyle), const SizedBox(width: 8), // 可选:添加间距 Expanded(child: Text(widget.rightText, style: widget.textStyle, overflow: TextOverflow.ellipsis)), ], ); } if (_rightTextWidth <= halfWidth && _leftTextWidth > halfWidth) { return Row( children: [ Expanded(child: Text(widget.leftText, style: widget.textStyle, overflow: TextOverflow.ellipsis)), const SizedBox(width: 8), Text(widget.rightText, style: widget.textStyle), ], ); } // 情况3:两个文本都长,按1:1平分 return Row( children: [ Flexible( flex: 1, child: Text(widget.leftText, style: widget.textStyle, overflow: TextOverflow.ellipsis), ), const SizedBox(width: 8), Flexible( flex: 1, child: Text(widget.rightText, style: widget.textStyle, overflow: TextOverflow.ellipsis), ), ], ); }, ); } } // 使用示例 void main() { runApp(const MaterialApp( home: Scaffold( body: Padding( padding: EdgeInsets.all(16.0), child: Column( spacing: 20, children: [ // 情况1:短文本 DynamicTextRow(leftText: 'blah', rightText: 'blah'), // 情况2:左长右短 DynamicTextRow(leftText: '这是一段非常长的文本内容,用来测试单个文本较长的场景', rightText: '短文本'), // 情况3:两个都长 DynamicTextRow( leftText: '这是左侧的超长文本,用来测试两个文本都很长的场景', rightText: '这是右侧的超长文本,用来测试两个文本都很长的场景', ), ], ), ), ), )); }
代码说明
TextPainter:用于预计算文本在无约束下的原始宽度,提前判断文本长度LayoutBuilder:获取Row的可用总宽度,作为布局判断的依据- 条件分支:分别对应三种场景,动态切换Row的布局方式
- 可选优化:添加
SizedBox作为文本间的间距,设置TextOverflow.ellipsis处理文本溢出
内容的提问来源于stack exchange,提问作者Yuzhao Shen
相关产品推荐
相关产品推荐

