基于包裹文本的子窗口小部件的复杂对齐,例如在Telegram聊天Messenger中 [英] Complex alignment of a sub widget based on wrapping text like in the Telegram chat messenger

查看:65
本文介绍了基于包裹文本的子窗口小部件的复杂对齐,例如在Telegram聊天Messenger中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的目标是复制用于其聊天消息气泡的复杂布局Telegram(以及其他一些聊天应用程序).气泡并不复杂,但是气泡中的文本与日期对齐得很好,这被证明是非常荒谬的:

类似的

理想情况下,日期将是一个单独的小部件,并且两者将与spaceBetween灵活对齐,因此日期始终如右图所示始终位于右下角.哦,我正在使用 bubble:^ 1.1.9 + 1 小部件来获取实际的聊天气泡.

解决方案

找到了解决方案,并且对它的简单性感到愚蠢,但不能抱怨,因为它完美地发挥了作用:

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

这里的魔术"是在邮件末尾添加30个左右的空格,以便仅在自动换行的文本小部件的底行提供足够的填充量.无需复杂或昂贵的重绘或布局逻辑.

请确保在字符串的末尾放置一个非打印字符,否则默认情况下,Flutter会在文本小部件上执行某种 trimRight(),并且它将无法正常工作.如果您从此处复制代码(和StackOverflow,请使用 U + 202F )不会自动删除这些字符,它应该可以工作.)

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

  Positioned(宽度:60,高度:9右:0,底部:0,子级:Row(mainAxisSize:MainAxisSize.min,mainAxisAlignment:MainAxisAlignment.end,子代:< Widget> [文本(DateFormat('H:mm a').format(_message.createdDate.toLocal()).toString(),样式:Theme.of(context).textTheme.caption.merge(TextStyle(fontSize:10)),textAlign:TextAlign.right,),填充(填充:const EdgeInsets.only(左:4.0),子代:图标(Icons.done_all,大小:13),)],),), 

My goal is to reproduce the complex layout Telegram (and a few other chat apps) use for their chat message bubbles. The bubble isn't complicated but having the text in the bubble align well with the date is proving to be ridiculously complicated:

A similar post has been made and answered here, but critically it does not handle wrapping text properly (cases #1 & #2 detailed below) as the padding-right remains constant wasting a lot of screen real estate and it looks bad. (See here if that wasn't clear: 2).

I've compiled what I believe are the 3 "use cases" to reproduce this layout in the image above:

Case #1: is by far the most complicated, it appears to be a small container for the date widget taking up the minimal amount of space, perhaps a row with mainAxisSize set to min. The complicated part is in how the text is allowed to flow above and beside while wrapping naturally to avoid any overlap.

Case #2: if #1 above were to overlap, due to a text line with an almost perfect amount of characters (so as to not wrap naturally), it would transition to the layout seen in case #2 below which appears to be a column with two nested rows.

Case #3: this is by far the easiest to achieve in isolation and can be done in many ways, the simplest being a single row with two text widgets. I'm fairly certain if a solution accomplishes #1 & #2 above, this one should be free.

What I've tried: Stacking the two, with the date being wrapped in a Positioned and something like bottom: 0, right: 15. This basically only achieves Case #1 if you add padding-right of at least 25.

I've also tried RichText which has been the most promising so far, it sort of handles all cases but is far less elegant that what telegram is doing. The major downside to this is I'll still have to use a some sort of Stack to place the "sent and seen" icon check-marks since Icons can't be included in RickText spans ...so I'll still need some padding right + bottom so they don't overlap. Here's the code for that and an image below:

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

Ideally the date would be a separate widget and the two would be flex aligned with spaceBetween so the date remains always in the bottom right corner like in the telegram images above. Oh and I'm using the bubble: ^1.1.9+1 widget for the actual chat bubbles.

解决方案

Found the solution and felt really dumb about how simple it is, but can't complain as it works perfectly:

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

The "magic" here is by adding 30 or so spaces to the end of your message you give the perfect amount of padding to only the bottom line of a wrapping text widget. No complex or expensive repaints or layout logic needed.

Make sure to put a non-printing character at the end of your string of spaces or Flutter will perform some sort of trimRight() on your Text Widget by default and it won't work. I used U+202F, if you copy the code from here (and StackOverflow doesn't auto-remove these characters it should work).

Put the above Text widget into a Stack with your date/icon positioned bottom-right like so:

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

这篇关于基于包裹文本的子窗口小部件的复杂对齐,例如在Telegram聊天Messenger中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆