【问题标题】:Complex alignment of a sub widget based on wrapping text like in the Telegram chat messenger基于包装文本的子小部件的复杂对齐,如 Telegram 聊天信使
【发布时间】:2020-03-14 10:03:14
【问题描述】:

我的目标是重现 Telegram(和其他一些聊天应用程序)用于聊天消息气泡的复杂布局。气泡并不复杂,但事实证明气泡中的文本与日期完全一致是非常复杂的:

类似的post has been made and answered here,但关键是它不能正确处理换行文本(下面详述的情况#1 和#2),因为 padding-right 一直在浪费大量屏幕空间并且看起来很糟糕。 (如果不清楚,请参阅此处:2)。

我已经编译了我认为是 3 个“用例”来重现上图中的这种布局:

案例 #1: 是迄今为止最复杂的,它似乎是一个小容器,用于容纳占用最小空间的日期小部件,可能是 mainAxisSize 设置为 min 的一行。复杂的部分在于如何允许文本在上方和旁边流动,同时自然换行以避免任何重叠。

案例 #2: 如果上面的 #1 重叠,由于文本行的字符数量几乎完美(以免自然换行),它将过渡到所见的布局如果下面的情况 #2 似乎是具有两个嵌套行的列。

案例#3:这是迄今为止最容易单独实现的,并且可以通过多种方式完成,最简单的方法是单行包含两个文本小部件。我相当肯定,如果一个解决方案完成了上面的 #1 和 #2,这个应该是免费的。

我尝试过的: 将两者堆叠在一起,日期用Positionedbottom: 0, right: 15 之类的东西包裹。如果您添加至少 25 的 padding-right,这基本上只能实现案例 #1。

我还尝试了迄今为止最有前途的 RichText,它可以处理所有情况,但远不如电报所做的优雅。这样做的主要缺点是我仍然必须使用某种堆栈来放置“发送和看到”图标复选标记,因为图标不能包含在 RickText 跨度中......所以我仍然需要一些填充右+下,使它们不重叠。这是代码和下面的图片:

RichText(
  text: TextSpan(
    text: _message.textContent,
    style: DefaultTextStyle.of(context).style.merge(TextStyle(fontSize: 16)),
    children: <TextSpan>[
      TextSpan(text: ' ' + DateFormat('H:mm a').format(_message.createdDate.toLocal()).toString(),
        style: Theme.of(context).textTheme.caption.merge(
          TextStyle(
            fontSize: 10,
          )
        ),
      ),
    ],
  ),
),

理想情况下,日期将是一个单独的小部件,并且两者将与 spaceBetween 灵活对齐,因此日期始终保持在右下角,就像上面的电报图像中一样。 哦,我正在使用 bubble: ^1.1.9+1 小部件作为实际聊天气泡。

【问题讨论】:

  • 如果你想获得每一行的边界,你需要使用TextPainterParagraph API

标签: flutter flutter-layout


【解决方案1】:

找到了解决方案,对它的简单程度感到非常愚蠢,但不能抱怨,因为它运行良好:

Text(
  _message.textContent + '                ',
  style: DefaultTextStyle.of(context).style.merge(TextStyle(fontSize: 16)),
),

这里的“魔力”是通过在消息末尾添加 30 个左右的空格,您可以仅在换行文本小部件的底行提供完美数量的填充。无需复杂或昂贵的重绘或布局逻辑。

确保在空格字符串的末尾放置一个非打印字符,否则默认情况下 Flutter 会在您的 Text Widget 上执行某种trimRight() 并且它不起作用。我使用了U+202F,如果你从这里复制代码(并且 StackOverflow 不会自动删除这些字符,它应该可以工作)。

将上面的 Text 小部件放入 Stack 中,日期/图标位于右下角,如下所示:

Positioned(
  width: 60,
  height: 9,
  right: 0,
  bottom: 0,
  child: Row(
    mainAxisSize: MainAxisSize.min,
    mainAxisAlignment: MainAxisAlignment.end,
    children: <Widget>[
      Text(
        DateFormat('H:mm a').format(_message.createdDate.toLocal()).toString(),
        style: Theme.of(context).textTheme.caption.merge(TextStyle(fontSize: 10)),
        textAlign: TextAlign.right,
      ),
      Padding(
        padding: const EdgeInsets.only(left: 4.0),
        child: Icon(Icons.done_all, size: 13),
      )
    ],
  ),
),

【讨论】:

  • 天哪,这很好用!比 SO 上发布的其他解决方案要简单得多。
  • 这确实有一个微妙的问题,但如果你接近像我这样的完美主义者。额外的空格计入文本的合理性,这意味着如果你将它与灵活的小部件结合使用,你会得到一些丑陋的右侧填充,而不是在多行文本字段中最长的最后一个单词下右对齐的日期。
  • @vipes 有截图吗?我无法想象它。
  • 好的,看看我提出的这个问题:stackoverflow.com/questions/66201124/…
猜你喜欢
  • 1970-01-01
  • 2015-08-10
  • 1970-01-01
  • 2021-12-10
  • 2011-03-01
  • 1970-01-01
  • 2019-11-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多