基于像 Telegram 聊天信使中那样的换行文本的子小部件的复杂对齐

alt*_*Dev 5 flutter

我的目标是重现 Telegram(以及其他一些聊天应用程序)用于聊天消息气泡的复杂布局。气泡并不复杂,但事实证明,让气泡中的文本与日期很好地对齐却异常复杂:

电报聊天气泡完美包裹的屏幕截图

类似的帖子已经在这里发布和回答,但关键的是它不能正确处理文本换行(下面详细介绍的情况#1和#2),因为填充右侧保持不变,浪费了大量的屏幕空间,而且看起来很糟糕。(如果还不清楚,请参见此处:2)。

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

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

情况#2:如果上面的#1 重叠,由于文本行的字符数量几乎完美(以便不会自然换行),它将转换到下面的情况#2 中看到的布局,这似乎是一个具有两个嵌套行的列。

情况#3:这是迄今为止最容易单独实现的,并且可以通过多种方式完成,最简单的是带有两个文本小部件的单行。我相当确定,如果解决方案能够实现上述#1 和#2,那么这个解决方案应该是免费的。

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

我还尝试过 RichText,它是迄今为止最有前途的,它可以处理所有情况,但远没有 telegram 所做的那么优雅。这样做的主要缺点是我仍然需要使用某种堆栈来放置“已发送和已查看”图标复选标记,因为图标不能包含在 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,
          )
        ),
      ),
    ],
  ),
),
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

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

alt*_*Dev 3

找到了解决方案,并对其如此简单的感觉感到非常愚蠢,但不能抱怨,因为它完美地工作:

\n\n
Text(\n  _message.textContent + \'               \xe2\x80\xaf\',\n  style: DefaultTextStyle.of(context).style.merge(TextStyle(fontSize: 16)),\n),\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

确保在空格字符串的末尾放置一个非打印字符,否则 FluttertrimRight()默认情况下会在您的文本小部件上执行某种操作,但它将无法工作。我使用了U+202F,如果你从这里复制代码(StackOverflow 不会自动删除这些字符,它应该可以工作)。

\n\n

将上面的文本小部件放入堆栈中,并将日期/图标放置在右下角,如下所示:

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