问题描述
我的目标是重现 Telegram(和其他一些聊天应用程序)用于其聊天消息气泡的复杂布局.气泡并不复杂,但事实证明气泡中的文本与日期完全一致是非常复杂的:
类似的
理想情况下,日期将是一个单独的小部件,并且两者将与 spaceBetween 灵活对齐,因此日期始终保持在右下角,就像上面的电报图像一样.哦,我正在使用 bubble: ^1.1.9+1
小部件作为实际聊天气泡.
找到了解决方案,对它的简单程度感到非常愚蠢,但不能抱怨,因为它运行良好:
文本(_message.textContent + ' ',样式:DefaultTextStyle.of(context).style.merge(TextStyle(fontSize: 16)),),
这里的魔力"是通过在消息末尾添加 30 个左右的空格,您可以仅在换行文本小部件的底行提供完美数量的填充.无需复杂或昂贵的重绘或布局逻辑.
确保在你的空格字符串末尾放置一个非打印字符,否则 Flutter 默认会在你的 Text Widget 上执行某种 trimRight()
并且它不会起作用.如果您从此处复制代码(以及 StackOverflow不会自动删除这些字符,它应该可以工作).
将上面的 Text 小部件放入 Stack 中,日期/图标位于右下角,如下所示:
定位(宽度: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,),填充(填充: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 聊天信使的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!