将消息时间戳与颤振消息文本字段的尾部右侧对齐

Posted

技术标签:

【中文标题】将消息时间戳与颤振消息文本字段的尾部右侧对齐【英文标题】:Right aligning message timestamp with trailing right-hand-side of flutter message text field 【发布时间】:2021-05-17 22:22:20 【问题描述】:

正如我在之前关于该主题的帖子 (Multi-line flutter text field occupies all of Flexible space with ugly right padding) 中提到的那样,我有点完美主义者。不幸的是,我的 Flutter layout-fu 没有我的野心那么强大。我正在创建一个消息传递应用程序,并且正在向消息框添加时间戳。到目前为止,我的代码(也感谢这个答案:Complex alignment of a sub widget based on wrapping text like in the Telegram chat messenger)是这样的:

创建行的代码:

  Widget getAppUserMessageRow() 
    return Row(
      crossAxisAlignment: CrossAxisAlignment.center,
      mainAxisAlignment: MainAxisAlignment.end,
      children: <Widget>[
        SizedBox(width: AppState.i.chatItemUserLeftInset),
        Flexible(
          fit: FlexFit.loose,
          child: message.cm.messageType.getMessageWidget(message),
        ),
      ],
    );
  

创建消息框本身的代码:

Widget build(BuildContext context) 
bool isFromAppUser = message.cm.isFromAppUser(AppState.i.activeUserId);

return Container(
  padding: EdgeInsets.symmetric(
    vertical: AppState.i.chatItemMessageVerticalInset),
  child:
  Container(
    decoration: BoxDecoration(
      color: isFromAppUser ? AppState.i.chatItemUserMessageBackgroundColour : Colors.white,
          //.withOpacity(!message.isFromAppUser ? 0.1 : 0.8),
      borderRadius: BorderRadius.only(
        topLeft: Radius.circular(isFromAppUser ? AppState.i.chatItemMessageBorderRadius : 0),
        topRight: Radius.circular(isFromAppUser ? 0 : AppState.i.chatItemMessageBorderRadius),
        bottomRight: Radius.circular(isFromAppUser ? AppState.i.chatItemMessageCurvedBorderRadius : AppState.i.chatItemMessageBorderRadius),
        bottomLeft: Radius.circular(isFromAppUser ? AppState.i.chatItemMessageBorderRadius : AppState.i.chatItemMessageCurvedBorderRadius),
      ),
      boxShadow: [
            BoxShadow(
              color: AppState.i.chatItemMessageBoxShadowColour,
              spreadRadius: AppState.i.chatItemMessageBoxShadowSpreadRadius,
              blurRadius: AppState.i.chatItemMessageBoxShadowBlurRadius,
              offset: AppState.i.chatItemMessageBoxShadowOffset, // changes position of shadow
            ),
          ],                
    ),
    padding: EdgeInsets.symmetric(
        vertical: AppState.i.chatItemMessageVerInset,
        horizontal: AppState.i.chatItemMessageHorInset),
    child: Stack(
      children: [
        Text(

            // WTF? This calculates enough space for the message receipt time to wrap
            message.cm.messageText + (isFromAppUser ? '              \u202F' : '        \u202F'),
            style: TextStyle(
              fontSize: AppState.i.chatItemMessageTextFontSize,
              color:
                  isFromAppUser ? AppState.i.chatItemMessageUserTextFontColour : AppState.i.chatItemMessageOtherUserTextFontColour,
            ),
            textWidthBasis: TextWidthBasis.longestLine,
          ),
          // This Positioned item creates the message timestamp in the area gained by adding the spaces above, assuming the spaces forced
          // The text field into adding an extra line.
          Positioned(
            width: 60,
            height: 15,
            right: 0,
            bottom: -2,
            child: Row(
              mainAxisSize: MainAxisSize.min,
              mainAxisAlignment: MainAxisAlignment.end,
              children: <Widget>[
                Text(
                  DateFormat.Hm().format(message.cm.messageDisplayTime(AppState.i.activeUserId)),
                  style: TextStyle(
                    fontSize: AppState.i.chatItemMessageTimeFontSize,
                    color: isFromAppUser ? AppState.i.chatItemMessageUserTimeFontColour : AppState.i.chatItemMessageOtherUserTimeFontColour,
                  ),
                  textAlign: TextAlign.right,
                ),
                !isFromAppUser ? Container() : 
                Padding(
                  padding: EdgeInsets.only(left: AppState.i.chatItemMessageReceiptLeftInset),
                  child: message.cm.getReadReceiptIcon()
                )
              ],
            ),
          ),              
      ],
    ),
  )
);

这里有一些好的和坏的例子 - 查看坏例子的右侧填充。时间戳应该与上面的文字更右对齐:

还有更多:

添加空格 + 不可打印字符为日期时间戳腾出空间 + 已读回执组合是一种天才技巧,但也有缺点。当文本接近时间戳将占据的空间时,它会推出正确的对齐方式。所以在某些情况下,根据上述情况,盒子会消耗不必要的空间。

那么,这可以解决,还是可以使用不同的布局来实现我正在寻找的效果?我不能使用任何计算量太大的东西,因为现在滚动长列表时性能相当不错。

为了让这个更具体一些,一些“固定”的例子。

【问题讨论】:

从 Xs 和复选标记看来,当文本气泡由于日期被强制放在自己的行上而变成双倍宽度时,您似乎不喜欢它,对吗? 不确定双倍宽度,但是是的,当额外的空格在最后一行文本的 RHS 上创建一个间隙时,时间不再在文本下右对齐。这在第二张图片的第二个坏例子中最为明显。 【参考方案1】:

示例:Message box with Timestamp

我觉得你可以试试这个方法:

    计算/模拟文本并检查消息是否与时间戳重叠。 如果重叠,加\n换行。否则,退回原件。

你需要以下东西:

    LayoutBuilder:文本小部件上方的 BoxConstraint TextPainter:模拟布局(还需要TextStyletextWidthBasis,否则可能会影响布局效果)

代码如下:

// assume 'message' is a String need to be displayed
...
LayoutBuilder(builder: (context, constraints) 
  final reserve = '            \u202F';

  final originalPainter = TextPainter(
    text: TextSpan(text: text, style: TextStyle(fontSize: 20)),
    textDirection: TextDirection.ltr,
    textWidthBasis: TextWidthBasis.longestLine,
  )..layout(maxWidth: constraints.maxWidth);

  final reservePainter = TextPainter(
    text: TextSpan(text: text + reserve, style: TextStyle(fontSize: 20)),
    textDirection: TextDirection.ltr,
    textWidthBasis: TextWidthBasis.longestLine,
  )..layout(maxWidth: constraints.maxWidth);

  final changeLine = reservePainter.width > originalPainter.width + 0.001 || reservePainter.height > originalPainter.height + 0.001;

  return Text(
    changeLine ? text+'\n' : text,
    ...
  )

【讨论】:

哇,这看起来棒极了,谢谢 - 我非常感谢您的努力。我只需要完成我目前正在做的工作,然后我会尝试一下——应该不会太长。 感谢您的回答。您能否分享完整的代码来完成这项工作?那么聊天气泡的完整代码呢?那太棒了!

以上是关于将消息时间戳与颤振消息文本字段的尾部右侧对齐的主要内容,如果未能解决你的问题,请参考以下文章

调整 UILabel 以对齐屏幕右侧

如何从 Smack 4.1 中的实时消息中获取服务器时间戳

KafkaKafka版本的 watermark 迟来的消息 直接报错

显示错误消息时颤振输入字段折叠

如何对齐两个大小不等的时间序列numpy数组?

以编程方式在 TextView 中设置文本对齐方式