当前位置: 首页 > news >正文

Flutter for OpenHarmony二手物品置换App实战 - 聊天对话实现

聊天功能是买卖双方沟通的核心,买家询问商品细节、协商价格、约定交易方式都在聊天中完成。今天我们来实现"闲置换"的聊天页面,包括消息气泡展示和消息发送功能。

聊天页面的设计思路

聊天页面的核心是消息列表和输入框。消息列表展示双方的对话,自己发的消息靠右显示绿色气泡,对方的消息靠左显示白色气泡。底部是输入框和发送按钮,支持快速发送文字消息。这种左右分布的布局是聊天界面的标准设计,用户一眼就能分清哪些是自己说的。

完整代码实现

import'package:flutter/material.dart';classChatPageextendsStatefulWidget{finalint userId;finalStringuserName;constChatPage({super.key,requiredthis.userId,requiredthis.userName});@overrideState<ChatPage>createState()=>_ChatPageState();}class_ChatPageStateextendsState<ChatPage>{finalTextEditingController_messageController=TextEditingController();finalScrollController_scrollController=ScrollController();finalList<Map<String,dynamic>>_messages=[{'isMe':false,'content':'你好,这个还在吗?','time':'10:30'},{'isMe':true,'content':'在的,有什么问题吗?','time':'10:31'},{'isMe':false,'content':'可以便宜点吗?','time':'10:32'},];

聊天页面接收userIduserName两个参数,用于显示对方的信息和发送消息时标识接收者。定义了两个Controller:_messageController控制输入框,可以获取用户输入的内容和清空输入框;_scrollController控制消息列表滚动,发送新消息后需要自动滚动到底部让用户看到最新消息。_messages是消息列表,每条消息包含是否是自己发的、消息内容、发送时间,实际项目中还需要消息id、发送状态等字段。

@overridevoiddispose(){_messageController.dispose();_scrollController.dispose();super.dispose();}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:Text(widget.userName),actions:[IconButton(icon:constIcon(Icons.more_vert),onPressed:(){}),],),body:Column(children:[Expanded(child:ListView.builder(controller:_scrollController,padding:constEdgeInsets.all(16),itemCount:_messages.length,itemBuilder:(context,index)=>_buildMessageBubble(_messages[index]),),),_buildInputBar(),],),);}

dispose方法释放两个Controller,这是Flutter开发的好习惯,避免内存泄漏。页面结构用Column垂直排列消息列表和输入框,Expanded让消息列表占据除输入框外的所有空间。AppBar显示对方的用户名,让用户知道是在和谁聊天,右边放更多按钮可以弹出举报、拉黑等选项。消息列表用ListView.builder实现懒加载,传入_scrollController用于控制滚动,padding给列表加内边距让消息不会贴着屏幕边缘。

Widget_buildMessageBubble(Map<String,dynamic>message){finalisMe=message['isMe']asbool;returnPadding(padding:constEdgeInsets.only(bottom:16),child:Row(mainAxisAlignment:isMe?MainAxisAlignment.end:MainAxisAlignment.start,crossAxisAlignment:CrossAxisAlignment.start,children:[if(!isMe)...[CircleAvatar(radius:18,backgroundColor:Colors.grey[300],child:Text(widget.userName[0],style:constTextStyle(fontSize:14)),),constSizedBox(width:8),],

消息气泡的布局根据是否是自己发的来决定对齐方式。自己的消息MainAxisAlignment.end靠右显示,对方的消息MainAxisAlignment.start靠左显示。crossAxisAlignment: CrossAxisAlignment.start让头像和气泡顶部对齐,如果消息很长换行了,头像不会跑到中间去。对方的消息前面显示头像,用CircleAvatar做成圆形,显示用户名的首字母,实际项目中应该显示真实头像图片。展开运算符...[]配合if实现条件渲染,只有对方的消息才显示头像。

Flexible(child:Container(padding:constEdgeInsets.symmetric(horizontal:14,vertical:10),decoration:BoxDecoration(color:isMe?constColor(0xFF07C160):Colors.white,borderRadius:BorderRadius.circular(16),),child:Text(message['content'],style:TextStyle(color:isMe?Colors.white:Colors.black87),),),),if(isMe)...[constSizedBox(width:8),CircleAvatar(radius:18,backgroundColor:constColor(0xFF07C160),child:constText('我',style:TextStyle(fontSize:14,color:Colors.white)),),],],),);}

消息气泡用Flexible包裹,这样长消息会自动换行而不是撑破布局超出屏幕。气泡用圆角矩形,自己的消息是绿色背景白色文字,对方的消息是白色背景黑色文字,这种配色方案和微信类似,用户很熟悉。自己的消息后面显示头像,绿色背景加"我"字,和对方的头像形成对比。padding给气泡内容加内边距,文字不会贴着边缘,阅读更舒适。

Widget_buildInputBar(){returnContainer(padding:constEdgeInsets.symmetric(horizontal:12,vertical:8),decoration:BoxDecoration(color:Colors.white,boxShadow:[BoxShadow(color:Colors.black.withOpacity(0.05),blurRadius:10,offset:constOffset(0,-2),),],),child:SafeArea(child:Row(children:[IconButton(icon:constIcon(Icons.add_circle_outline,color:Colors.grey),onPressed:(){},),

输入栏用Container包裹,加上向上的阴影让它看起来悬浮在消息列表上方,有层次感。SafeArea确保在有底部安全区域的设备上输入框不会被遮挡,比如iPhone的Home Indicator区域。左边放一个加号按钮,点击可以展开更多功能,比如发送图片、位置、商品链接等,这些功能在二手交易场景中很实用,卖家可以发送商品图片,买家可以发送收货地址。

Expanded(child:TextField(controller:_messageController,decoration:InputDecoration(hintText:'输入消息...',hintStyle:TextStyle(color:Colors.grey[400]),filled:true,fillColor:Colors.grey[100],contentPadding:constEdgeInsets.symmetric(horizontal:16,vertical:8),border:OutlineInputBorder(borderRadius:BorderRadius.circular(20),borderSide:BorderSide.none,),),),),constSizedBox(width:8),GestureDetector(onTap:_sendMessage,child:Container(padding:constEdgeInsets.all(10),decoration:constBoxDecoration(color:Color(0xFF07C160),shape:BoxShape.circle,),child:constIcon(Icons.send,color:Colors.white,size:20),),),],),),);}

输入框用Expanded占据中间的空间,圆角胶囊形状,灰色背景,看起来简洁现代。contentPadding控制文字和边框的距离,让输入框看起来不会太挤。发送按钮是一个绿色圆形,里面放发送图标,用GestureDetector处理点击比IconButton更灵活,可以自定义按钮的样式和大小。点击发送按钮调用_sendMessage方法发送消息。

void_sendMessage(){if(_messageController.text.trim().isEmpty)return;setState((){_messages.add({'isMe':true,'content':_messageController.text,'time':'${DateTime.now().hour}:${DateTime.now().minute}',});});_messageController.clear();Future.delayed(constDuration(milliseconds:100),(){_scrollController.animateTo(_scrollController.position.maxScrollExtent,duration:constDuration(milliseconds:300),curve:Curves.easeOut,);});}}

发送消息的方法先检查输入是否为空,trim()去掉首尾空格,避免发送纯空格的无意义消息。然后往消息列表添加新消息,isMe: true表示是自己发的,时间用当前时间。_messageController.clear()清空输入框,方便用户继续输入下一条消息。Future.delayed延迟100毫秒后滚动到底部,这个延迟是为了等待setState完成UI更新,新消息渲染出来后再滚动。animateTo带动画地滚动到maxScrollExtent也就是列表底部,Curves.easeOut让滚动有一个减速的效果,看起来更自然流畅。

聊天功能的扩展

实际项目中聊天功能还需要这些能力:消息类型扩展支持图片、语音、位置、商品卡片等;消息状态显示发送中、已发送、已读等状态;历史消息加载打开聊天页面时加载最近的消息,往上滚动时加载更早的历史消息;实时消息接收用WebSocket保持长连接,对方发消息时实时显示在列表中。

小结

这篇实现了"闲置换"App的聊天页面,包括消息气泡的左右布局、输入框和发送功能。自己的消息绿色靠右,对方的消息白色靠左,发送后自动滚动到底部。这是一个基础的聊天功能,实际项目中还需要扩展更多消息类型和功能。


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

http://www.jsqmd.com/news/290600/

相关文章:

  • 基于Spring Boot的爱老助老老年人健康服务平台vue3
  • layui上传组件连续上传同一个文件upload组件无反应
  • ServiceNow将OpenAI模型集成至其AI平台
  • 针对DBeaver连接IoTDB时无法连接的情况,没有IoTDB驱动,无法连接表模型
  • 如何将 Minio DirectPV 配置为 RustFS 存储后端?
  • 文科论述深度改写|挑战哲学论述文,“快降重”如何应对思辨文本?
  • SSA-VMD麻雀搜索算法优化变分模态分解+皮尔逊系数+小波阈值降噪+信号重构,MATLAB代码 - 教程
  • 基于Springcloud的智能社区服务系统vue3 门禁报修缴费停车
  • python 大学生身体健康体检管理系统有ue3
  • 高性价比榜单!2026年值得关注的小程序开发公司大比拼
  • Java毕设选题推荐:基于 SpringBoot+vue的电竞比赛管理系统的设计与实现基于springboot的电竞赛事中心设计系统【附源码、mysql、文档、调试+代码讲解+全bao等】
  • python 工商局商家年检管理系统vue3
  • python便民医疗服务预约系统 微信小程序vue3
  • Java毕设选题推荐:基于springboot的个性化音乐推荐系统基于用户音乐个性化推荐系统【附源码、mysql、文档、调试+代码讲解+全bao等】
  • python在线考试系统vue3
  • Java毕设选题推荐:基于springboot的手机通话套餐智慧通讯业务办理3D可视化平台【附源码、mysql、文档、调试+代码讲解+全bao等】
  • 踩坑三天,我终于搞懂了如何让多个AI助手在浏览器里“和平共处“
  • 【计算机毕业设计案例】基于springboot的演出网站订票系统基于SpringBoot+vue的演出购票系统(程序+文档+讲解+定制)
  • 【计算机毕业设计案例】基于JAVA的高校食堂在线点餐系统的设计与实现基于springboot框架的校园食堂外卖点餐系统基于springboot的高校食堂点餐系统(程序+文档+讲解+定制)
  • 【计算机毕业设计案例】基于springboot的智慧物联卡手机卡流量卡通讯业务办理3D可视化平台(程序+文档+讲解+定制)
  • 大数据时代,ETL 如何助力数据挖掘
  • 地砖屏如何优化展厅空间利用率?
  • 数学_大鹏_杠上整理_初一(上)_板块02-平面直角坐标系
  • 计算机Java毕设实战-基于springboot的电竞赛事中心设计系统基于SpringBoot的电竞赛事购票系统【完整源码+LW+部署说明+演示视频,全bao一条龙等】
  • 计算机Java毕设实战-基于springboot的话剧文艺演出网站订票系统【完整源码+LW+部署说明+演示视频,全bao一条龙等】
  • 计算机Java毕设实战-基于springboot的高校食堂在线点餐系统基于springboot的高校食堂点餐系统【完整源码+LW+部署说明+演示视频,全bao一条龙等】
  • HDFS 入门指南:大数据存储的基石与核心原理
  • 学术写作必备:9款论文查重工具及实用技巧详细排行
  • 计算机Java毕设实战-基于springboot的流量物联卡智慧通讯业务办理3D可视化平台【完整源码+LW+部署说明+演示视频,全bao一条龙等】
  • 精选9款论文查重工具:高效检测软件与技巧全面解析