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

Flutter如何实现文本中间截断且末尾ID始终可见?

解决方案

你的问题在于RichText的overflow是对整个文本内容生效的,无法单独针对某个子TextSpan做截断处理,所以会导致ID文本可能被截断,或者省略号位置不符合预期。要实现主文本溢出截断显示省略号,末尾ID始终保留的效果,有两种可行方案:

方案一:自定义布局计算(支持多行截断+ID同行显示)

通过TextPainter计算ID文本的宽度,再结合LayoutBuilder获取可用空间,让主文本在剩余空间内自动截断,最后拼接ID文本。这种方式能严格实现你示例中的两行截断效果,ID和省略号在同一行末尾。

实现代码

class TruncatedTextWithId extends StatefulWidget {
  final String mainText;
  final String idText;
  final TextStyle mainStyle;
  final TextStyle idStyle;
  final int maxLines;

  const TruncatedTextWithId({
    super.key,
    required this.mainText,
    required this.idText,
    required this.mainStyle,
    required this.idStyle,
    this.maxLines = 2,
  });

  @override
  State<TruncatedTextWithId> createState() => _TruncatedTextWithIdState();
}

class _TruncatedTextWithIdState extends State<TruncatedTextWithId> {
  late double _idTextWidth;

  @override
  void initState() {
    super.initState();
    // 预计算ID文本的占用宽度
    final idPainter = TextPainter(
      text: TextSpan(text: widget.idText, style: widget.idStyle),
      maxLines: 1,
      textDirection: TextDirection.ltr,
    )..layout();
    _idTextWidth = idPainter.width;
  }

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        // 计算主文本的可用宽度(减去ID宽度和间距)
        final availableWidth = constraints.maxWidth - _idTextWidth - 8;
        
        // 处理主文本的截断逻辑
        final mainPainter = TextPainter(
          text: TextSpan(text: widget.mainText, style: widget.mainStyle),
          maxLines: widget.maxLines,
          textDirection: TextDirection.ltr,
          ellipsis: '...',
        )..layout(maxWidth: availableWidth);

        return RichText(
          text: TextSpan(
            children: [
              TextSpan(text: mainPainter.text.toPlainText(), style: widget.mainStyle),
              const TextSpan(text: ' '),
              TextSpan(text: widget.idText, style: widget.idStyle),
            ],
          ),
        );
      },
    );
  }
}

使用方式

valueWidget: TruncatedTextWithId(
  mainText: '${organisation.displayName} Really, Really Long Company Name',
  idText: 'GB ${organisation.id}',
  mainStyle: theme.textTheme(textColor: theme.secondary.defaultColor.value).headline5!,
  idStyle: theme.textTheme(textColor: theme.neutral.dark1Color.value).headline5!,
  maxLines: 2,
),

方案二:Row+Expanded(简单场景适用)

如果你的布局允许ID在主文本溢出后换行显示,这种方式更简洁。主文本用Expanded包裹,自动占满剩余空间并截断,ID文本始终显示在右侧。

实现代码

valueWidget: Row(
  crossAxisAlignment: CrossAxisAlignment.end,
  children: [
    Expanded(
      child: Text(
        '${organisation.displayName} Really, Really Long Company Name',
        maxLines: 2,
        overflow: TextOverflow.ellipsis,
        style: theme.textTheme(textColor: theme.secondary.defaultColor.value).headline5,
      ),
    ),
    const SizedBox(width: 8),
    Text(
      'GB ${organisation.id}',
      style: theme.textTheme(textColor: theme.neutral.dark1Color.value).headline5,
    ),
  ],
),

原代码问题说明

你之前用RichText的方式,overflow会作用于整个TextSpan组合的文本,当总长度超过限制时,省略号会添加在整个文本的末尾,可能会覆盖或截断ID文本,无法实现主文本单独截断的效果。

内容的提问来源于stack exchange,提问作者EvGeniy Ilyin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 20:20:31