Flutter 聊天气泡文本未对齐

时间:2021-02-10 21:24:38

标签: android ios flutter dart

我正在使用 Flutter 构建一个聊天应用程序。

在我的消息气泡中,我会显示消息文本、日期和一个图标,以显示消息是否已被阅读。消息文本显示不佳。它会在一两个词之后转到下一行,而不是填充气泡的整个宽度。

screenshot of the problem

Container(
  padding: EdgeInsets.symmetric(
  horizontal: 15.0, vertical: 10.0),
  width: MediaQuery.of(context).size.width * 0.65,
  margin: EdgeInsets.only(top: 8.0, bottom: 8.0, left: 80.0, right: 10),
  decoration: BoxDecoration(
    color: primaryColor.withOpacity(.1),
    borderRadius: BorderRadius.circular(20)),
  child: Column(
    children: <Widget>[
      Row(
        crossAxisAlignment: CrossAxisAlignment.end,
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          Expanded(
            child: Container(
              child: Text(
                documentSnapshot.data['text'],
                style: TextStyle(
                  color: Colors.black87,
                  fontSize: 16.0,
                  fontWeight: FontWeight.w600,
                ),
              ),
            ),
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.end,
            children: <Widget>[
              Text(
                documentSnapshot.data["time"] != null
                  ? DateFormat.MMMd().add_jm()
                    .format(documentSnapshot.data["time"].toDate())
                    .toString()
                  : "",
                style: TextStyle(
                  color: secondryColor,
                  fontSize: 13.0,
                  fontWeight: FontWeight.w600,
                ),
              ),
              SizedBox(width: 5),
              documentSnapshot.data['isRead'] == false
                ? Icon(
                    Icons.done,
                    color: secondryColor,
                    size: 15,
                  )
                : Icon(
                    Icons.done_all,
                    color: primaryColor,
                    size: 15,
                  )
              ],
            ),

1 个答案:

答案 0 :(得分:2)

简答

目前,您使用 Row 小部件将消息文本显示为第一个子项,然后将日期和阅读图标显示为第二个子项:

enter image description here

相反,您应该使用 Column 小部件。

enter image description here

完整解决方案

和朱利安来回走后

enter image description here

1.领域层

class ChatEntry {
  final String text;
  final DateTime date;
  final bool read;
  final bool sent;

  ChatEntry({
    this.text,
    this.date,
    this.read,
    this.sent,
  });
}

2.聊天气泡

class Bubble extends StatelessWidget {
  final ChatEntry entry;

  const Bubble({Key key, this.entry}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Align(
      alignment: entry.sent ? Alignment.centerRight : Alignment.centerLeft,
      child: Container(
        padding: kBubblePadding,
        decoration: BoxDecoration(
          color: (entry.sent ? kSentColor : kReceivedColor)
              .withOpacity(entry.read ? kReadOpacity : 1),
          borderRadius: BorderRadius.only(
            topLeft: Radius.circular(kBorderRadius),
            topRight: Radius.circular(kBorderRadius),
            bottomRight: Radius.circular(entry.sent ? 0.0 : kBorderRadius),
            bottomLeft: Radius.circular(entry.sent ? kBorderRadius : 0.0),
          ),
        ),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment:
              entry.sent ? CrossAxisAlignment.end : CrossAxisAlignment.start,
          children: <Widget>[
            Text(entry.text, style: kBubbleTextStyle),
            Row(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                Text(
                  DateFormat('MMMd – kk:mm').format(entry.date),
                  style: TextStyle(fontSize: kBubbleMetaFontSize),
                ),
                if (entry.read) ...[
                  const SizedBox(width: 5),
                  Icon(Icons.done, size: kBubbleMetaFontSize)
                ]
              ],
            ),
          ],
        ),
      ),
    );
  }
}

3.聊天对话

class Conversation extends StatelessWidget {
  final List<ChatEntry> entries;

  const Conversation({Key key, this.entries}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Column(
      children: entries
          .map(
            (entry) => Padding(
              padding: const EdgeInsets.all(8.0),
              child: Bubble(entry: entry),
            ),
          )
          .toList(),
    );
  }
}

4.应用

void main() {
  runApp(
    MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Chat Demo',
      home: Scaffold(
        body: SingleChildScrollView(
          child: Conversation(entries: getChatEntries()),
        ),
      ),
    ),
  );
}

完整的源代码,便于复制粘贴

连同随机数据生成。

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:faker/faker.dart';

void main() {
  runApp(
    MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Chat Demo',
      home: Scaffold(
        body: SingleChildScrollView(
          child: Conversation(entries: getChatEntries()),
        ),
      ),
    ),
  );
}

class Conversation extends StatelessWidget {
  final List<ChatEntry> entries;

  const Conversation({Key key, this.entries}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Column(
      children: entries
          .map(
            (entry) => Padding(
              padding: const EdgeInsets.all(8.0),
              child: Bubble(entry: entry),
            ),
          )
          .toList(),
    );
  }
}

class Bubble extends StatelessWidget {
  final ChatEntry entry;

  const Bubble({Key key, this.entry}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Align(
      alignment: entry.sent ? Alignment.centerRight : Alignment.centerLeft,
      child: Container(
        padding: kBubblePadding,
        decoration: BoxDecoration(
          color: (entry.sent ? kSentColor : kReceivedColor)
              .withOpacity(entry.read ? kReadOpacity : 1),
          borderRadius: BorderRadius.only(
            topLeft: Radius.circular(kBorderRadius),
            topRight: Radius.circular(kBorderRadius),
            bottomRight: Radius.circular(entry.sent ? 0.0 : kBorderRadius),
            bottomLeft: Radius.circular(entry.sent ? kBorderRadius : 0.0),
          ),
        ),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment:
              entry.sent ? CrossAxisAlignment.end : CrossAxisAlignment.start,
          children: <Widget>[
            Text(entry.text, style: kBubbleTextStyle),
            Row(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                Text(
                  DateFormat('MMMd – kk:mm').format(entry.date),
                  style: TextStyle(fontSize: kBubbleMetaFontSize),
                ),
                if (entry.read) ...[
                  const SizedBox(width: 5),
                  Icon(Icons.done, size: kBubbleMetaFontSize)
                ]
              ],
            ),
          ],
        ),
      ),
    );
  }
}

// DOMAIN

class ChatEntry {
  final String text;
  final DateTime date;
  final bool read;
  final bool sent;

  ChatEntry({
    this.text,
    this.date,
    this.read,
    this.sent,
  });
}

// CONFIG

const kSentColor = Color(0xff03bd85);
const kReceivedColor = Color(0xff0251d6);
const kReadOpacity = .3;
const kBorderRadius = 15.0;
const kBubblePadding = const EdgeInsets.symmetric(
  horizontal: 15.0,
  vertical: 10.0,
);
const kBubbleTextStyle = const TextStyle(
  color: Colors.black87,
  fontSize: 16.0,
  fontWeight: FontWeight.w600,
);
const kBubbleMetaFontSize = 11.0;

// RANDOM DATA

final Random random = Random.secure();
final faker = new Faker();

List<ChatEntry> getChatEntries() {
  final nbMessages = random.nextInt(17) + 3;
  final lastRead = random.nextInt(nbMessages);
  DateTime date = DateTime.now();
  return List.generate(
    nbMessages,
    (index) {
      date = date.subtract(Duration(minutes: random.nextInt(30)));
      return ChatEntry(
        text: faker.lorem
            .words(2 + random.nextInt(random.nextBool() ? 3 : 15))
            .join(' '),
        date: date,
        read: index >= lastRead,
        sent: random.nextBool(),
      );
    },
  ).reversed.toList();
}
相关问题