在这里插入图片描述

前言

聊天气泡是即时通讯和社交应用中最核心的UI组件之一。一个优秀的聊天气泡组件需要能够区分发送方和接收方、支持多种消息类型、具备良好的视觉效果和交互体验。本文将深入讲解如何在Flutter和OpenHarmony平台上构建专业级的聊天气泡组件,涵盖样式定制、布局适配和性能优化等关键技术点。

Flutter聊天气泡组件实现

我们首先来实现Flutter版本的聊天气泡组件,这个组件将支持区分消息发送方向和自适应内容宽度。

class ChatBubble extends StatelessWidget {
  final String message;
  final bool isSentByMe;
  final String time;
  
  const ChatBubble({
    Key? key,
    required this.message,
    required this.isSentByMe,
    required this.time,
  }) : super(key: key);

组件定义了三个核心属性:message存储消息文本内容,isSentByMe布尔值标识消息是否由当前用户发送,time记录消息发送时间。这种设计遵循单一职责原则,组件只负责消息的展示,数据的获取和处理由上层组件负责。使用required关键字确保必要参数不会被遗漏。

  
  Widget build(BuildContext context) {
    return Align(
      alignment: isSentByMe 
        ? Alignment.centerRight 
        : Alignment.centerLeft,
      child: Container(
        margin: EdgeInsets.symmetric(
          horizontal: 16,
          vertical: 4,
        ),
        constraints: BoxConstraints(
          maxWidth: MediaQuery.of(context).size.width * 0.7,
        ),

Align组件根据消息发送方向决定气泡的对齐方式,发送的消息靠右,接收的消息靠左。Container的margin设置提供了适当的间距,constraints限制气泡最大宽度为屏幕宽度的70%,这个比例经过大量社交应用的实践验证,既能保证长消息的可读性,又不会让短消息显得过于空旷。

        padding: EdgeInsets.symmetric(
          horizontal: 16,
          vertical: 10,
        ),
        decoration: BoxDecoration(
          color: isSentByMe 
            ? Color(0xFF007AFF) 
            : Color(0xFFE5E5EA),
          borderRadius: BorderRadius.only(
            topLeft: Radius.circular(18),
            topRight: Radius.circular(18),
            bottomLeft: Radius.circular(isSentByMe ? 18 : 4),
            bottomRight: Radius.circular(isSentByMe ? 4 : 18),
          ),
        ),

内边距的设置让文字与气泡边缘保持舒适的距离。颜色方案采用经典的蓝色(发送)和灰色(接收)搭配,这是iOS Messages应用的设计语言,用户接受度很高。圆角的不对称设计是现代聊天应用的标志性特征,发送消息的右下角和接收消息的左下角使用较小的圆角,形成指向效果,增强了消息的方向感。

        child: Column(
          crossAxisAlignment: CrossAxisAlignment.end,
          children: [
            Text(
              message,
              style: TextStyle(
                color: isSentByMe 
                  ? Colors.white 
                  : Colors.black87,
                fontSize: 16,
              ),
            ),

Column组件垂直排列消息内容和时间戳,crossAxisAlignment设置为end使时间戳右对齐。消息文本的颜色根据气泡背景色自动调整,确保足够的对比度和可读性。字体大小16像素是移动端阅读的最佳尺寸,既不会太小难以辨认,也不会太大浪费空间。

            SizedBox(height: 4),
            Text(
              time,
              style: TextStyle(
                color: isSentByMe 
                  ? Colors.white70 
                  : Colors.black45,
                fontSize: 11,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

时间戳使用较小的字号和较低的不透明度,作为辅助信息不会干扰主要内容的阅读。SizedBox提供4像素的间距,让布局更加紧凑。这种层次分明的信息展示方式符合视觉设计的基本原则。

OpenHarmony ArkTS实现

现在让我们看看如何在鸿蒙系统上实现相同功能的聊天气泡组件。

@Component
struct ChatBubble {
  @Prop message: string = ''
  @Prop isSentByMe: boolean = false
  @Prop time: string = ''
  
  private bubbleColor(): ResourceColor {
    return this.isSentByMe ? '#007AFF' : '#E5E5EA'
  }

ArkTS组件同样使用@Prop接收外部属性。我们定义了一个私有方法bubbleColor来返回气泡颜色,这种封装方式让代码更加清晰,也便于后续扩展主题切换功能。ResourceColor类型是鸿蒙系统中颜色资源的标准类型。

  private textColor(): ResourceColor {
    return this.isSentByMe ? Color.White : '#1C1C1E'
  }

  build() {
    Row() {
      if (!this.isSentByMe) {
        Blank()
      }

textColor方法同样封装了文字颜色的逻辑。build方法中使用Row作为根容器,通过Blank组件实现消息的左右对齐。当消息不是自己发送时,在左侧添加Blank占位,将气泡推向右侧。这是ArkTS中实现弹性布局的常用技巧。

      Column() {
        Text(this.message)
          .fontSize(16)
          .fontColor(this.textColor())
          .padding({ left: 16, right: 16, top: 10, bottom: 4 })

Column组件包裹消息内容和时间戳。Text组件通过链式调用设置字体大小、颜色和内边距。ArkTS的padding属性支持分别设置四个方向的值,语法更加灵活。底部padding较小是为了给时间戳留出空间。

        Text(this.time)
          .fontSize(11)
          .fontColor(this.isSentByMe ? '#FFFFFFB3' : '#0000007A')
          .padding({ left: 16, right: 16, bottom: 10 })
      }
      .backgroundColor(this.bubbleColor())
      .borderRadius({
        topLeft: 18,
        topRight: 18,
        bottomLeft: this.isSentByMe ? 18 : 4,
        bottomRight: this.isSentByMe ? 4 : 18
      })

时间戳的颜色使用带透明度的十六进制值,B3对应约70%不透明度,7A对应约48%不透明度。borderRadius属性支持分别设置四个角的圆角值,实现与Flutter版本相同的不对称圆角效果。

      .constraintSize({ maxWidth: '70%' })
      .alignItems(HorizontalAlign.End)

      if (this.isSentByMe) {
        Blank()
      }
    }
    .width('100%')
    .padding({ left: 16, right: 16, top: 4, bottom: 4 })
  }
}

constraintSize限制气泡最大宽度,alignItems设置内容右对齐。当消息是自己发送时,在右侧添加Blank将气泡推向左侧。整个Row设置100%宽度和适当的padding,确保在不同屏幕尺寸下都有良好的显示效果。

消息列表集成示例

在Flutter中,聊天气泡通常与ListView配合使用:

ListView.builder(
  reverse: true,
  itemCount: messages.length,
  itemBuilder: (context, index) {
    final msg = messages[index];
    return ChatBubble(
      message: msg.content,
      isSentByMe: msg.senderId == currentUserId,
      time: formatTime(msg.timestamp),
    );
  },
)

reverse属性设置为true使列表从底部开始显示,这是聊天界面的标准行为。itemBuilder根据消息数据动态创建气泡组件,通过比较发送者ID判断消息方向。

总结

本文详细介绍了聊天气泡组件在Flutter和OpenHarmony两个平台上的实现方案。聊天气泡看似简单,但要做好需要考虑很多细节,包括颜色对比度、圆角设计、宽度限制、时间戳展示等。两个平台的实现思路基本一致,都采用条件渲染和样式计算来区分消息方向。在实际项目中,还可以扩展支持图片消息、语音消息、表情包等多种消息类型。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐