You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现Row中两个Flexible组件的自适应弹性布局?

实现动态分配宽度的Row布局

要满足你提出的三种布局场景,单纯依赖Flexible/Expanded无法实现动态调整逻辑,需要结合文本宽度预计算和条件布局来处理。以下是具体实现方案:

核心思路

  1. 预计算两个文本在无约束下的原始宽度
  2. 获取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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 09:05:22