Flutter 基于包装文本(如电报聊天信使中的文本)的子小部件的复杂对齐

Flutter 基于包装文本(如电报聊天信使中的文本)的子小部件的复杂对齐,flutter,flutter-layout,Flutter,Flutter Layout,我的目标是重现用于聊天信息气泡的复杂布局电报(和一些其他聊天应用程序)。泡泡并不复杂,但让泡泡中的文字与日期很好地对齐被证明是非常复杂的: 一个类似的,但关键是它不能正确处理包装文本(下面详细介绍了案例1和案例2),因为填充权保持不变,浪费了大量屏幕空间,而且看起来很糟糕。(如果不清楚,请参见此处:) 我已经编译了我认为是3个“用例”来重现上图中的布局: 案例#1:是迄今为止最复杂的,它似乎是日期小部件的一个小容器,占用了最小的空间,可能是一行mainAxisSize设置为min。复杂的部分在

我的目标是重现用于聊天信息气泡的复杂布局电报(和一些其他聊天应用程序)。泡泡并不复杂,但让泡泡中的文字与日期很好地对齐被证明是非常复杂的:

一个类似的,但关键是它不能正确处理包装文本(下面详细介绍了案例1和案例2),因为填充权保持不变,浪费了大量屏幕空间,而且看起来很糟糕。(如果不清楚,请参见此处:)

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

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

Case#2:如果上面的#1重叠,由于文本行的字符数量几乎完美(因此不会自然换行),它将过渡到下面的Case#2中所示的布局,该布局看起来是一个包含两个嵌套行的列

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

我所尝试的: 将二者堆叠起来,日期被包装在一个
位置
中,类似于
底部:0,右侧:15。这基本上只在至少添加25个填充的情况下实现情况#1

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

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,
          )
        ),
      ),
    ],
  ),
),
RichText(
text:TextSpan(
text:_message.textContent,
style:DefaultTextStyle.of(context.style.merge)(TextStyle(fontSize:16)),
儿童:[
TextSpan(文本:“”+DateFormat('H:mm a')。格式(_message.createdDate.toLocal())。toString(),
样式:Theme.of(context).textTheme.caption.merge(
文本样式(
尺寸:10,
)
),
),
],
),
),

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

找到了解决方案,对它的简单性感到非常愚蠢,但不能抱怨,因为它工作得非常完美:

Text(
  _message.textContent + '                ',
  style: DefaultTextStyle.of(context).style.merge(TextStyle(fontSize: 16)),
),
这里的“魔力”是在消息的末尾添加30个左右的空格,这样你就只给包装文本小部件的底线添加了完美的填充量。不需要复杂或昂贵的重新绘制或布局逻辑

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

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

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),
      )
    ],
  ),
),
定位(
宽度:60,
身高:9,
右:0,,
底部:0,
孩子:排(
mainAxisSize:mainAxisSize.min,
mainAxisAlignment:mainAxisAlignment.end,
儿童:[
正文(
DateFormat('H:mm a').format(_message.createdDate.toLocal()).toString(),
样式:Theme.of(context).textTheme.caption.merge(TextStyle(fontSize:10)),
textAlign:textAlign.right,
),
填充物(
填充:仅限常量边集(左:4.0),
子项:图标(Icons.done_all,大小:13),
)
],
),
),

如果你想得到每一行的边界,你需要使用
textpainer
段落
这很好!这比其他的解决方案要简单得多。但如果你像我一样接近完美主义者,这确实有一个微妙的问题。额外的空格用于证明文本的合理性,这意味着如果您将其与一个灵活的小部件相结合,您将得到一些难看的右侧填充,而不是在多行文本字段中最长的最后一个单词下将日期右对齐。@vipes有屏幕截图吗?我无法想象。当然,看看我提出的这个问题: