右对齐消息时间戳与 flutter 消息文本字段的尾随右侧

Right aligning message timestamp with trailing right-hand-side of flutter message text field

正如我在之前的 post 主题 () I'm a bit of a perfectionist. Unfortunately my flutter layout-fu isn't as strong as my ambition. I'm creating a messaging app, and I'm working on adding a timestamp to the message box. My code so far (thanks also to this answer: ) 中提到的那样:

创建一行的代码:

  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()
                )
              ],
            ),
          ),              
      ],
    ),
  )
);

}

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

还有更多:

添加 spaces + 一个不可打印的字符来为日期时间戳 + 已读回执组合腾出空间是一个天才的把戏,但也有缺点。当文本接近将被时间戳占用的 space 时,它会推出右对齐。所以在某些情况下,根据上述情况,盒子会消耗不必要的 space.

那么,是否可以解决这个问题,或者是否可以使用不同的布局来实现我正在寻找的效果?我不能使用太过计算的东西,因为现在滚动长列表时性能相当不错。

为了使这个更具体一些,一些 'fixed' 个例子。

示例:Message box with Timestamp

我想你可以这样试试:

  1. Calculate/Simulate 文本并检查消息是否与时间戳重叠。
  2. 如果重叠,添加\n来换行。否则,return原来的

你需要以下东西:

  1. LayoutBuilder: 文本控件上方的 BoxConstraint
  2. 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,
    ...
  )
}