DuiLib实现仿微信聊天界面

DuiLib实现聊天界面

特别说明,这里是基于 网易的修改版DuiLib 演示,非原生,请特别注意!下文中为了和DuiLib有所区别,称其为NimDuiLib。

界面分析

利用好 蓝湖 和 Sketch 工具,可以大大提高我们的开发效率,Sketch是Mac下面的一款界面设计工具,而蓝湖是一个网站,可以把Sketch设计好的作品进行切图和标注,再也不用通过截图工具算PX了。

这里以(参考Telegram使用Sketch设计)下图为例:
在这里插入图片描述
在这里插入图片描述

我们可以看到,整个界面主要分成2块:

  • 左侧会话界面:主要是显示单聊、群聊和其他的一些比如微信里面有公众号、新闻、订阅号等一下列表。
  • 右侧聊天输入框和消息界面。

我们先来看一下,会话列表通过DuiLib如何实现。

整体结构

思路

如果有过DuiLib开发经验的人,可能一眼就能知道左侧是1个ListBox,右侧是1个TabBox,那对于我们初学者而言怎么办?

有个很好的思路:去Github上搜一搜(duilib),或者使用搜索引擎搜索关键字(duilib、duilib仿微信),看看别人是怎么实现的。这里我们就找到了 网易云IM的WindowsDemo ,通过运行和研究它的代码,了解了聊天界面的实现原理,有时间的朋友,推荐去看一看。
在这里插入图片描述

布局和代码

分析出了界面构成,这个时候就好办了,我们先把布局实现出来。

<?xml version="1.0" encoding="UTF-8"?>
<Window size="800,560" caption="0,0,0,35"><VBox><!-- 标题 --><HBox class="caption"><Button class="btn_wnd_close" name="closebtn" float="true" margin="8,5,0,0" /><Button class="btn_wnd_min" name="minbtn" float="true" margin="28,5,0,0" /><Label text="Telegram" margin="51,2,51,0" align="center" width="277"></Label></HBox><HBox><!-- 左侧菜单栏 --><VBox width="55" bkcolor="white"><Control bkimage="../public/headmask/icon_headimage_mask_50x50_normal.png" width="36" height="36" margin="9,34,10,0" /><Control bkimage="msg_normal.png" width="36" height="36" margin="9,35,10,0" /><Control bkimage="contact_normal.png" width="36" height="36" margin="9,35,10,0" /><Control bkimage="setting_normal.png" width="36" height="36" margin="9,35,10,0" /></VBox><Control class="splitline_ver_level1" width="1" mouse="false" /><!-- 好友列表 --><VBox width="300" bkcolor="white"><HBox height="53"><RichEdit class="simple input" rich="false" padding="5,6,5,0" margin="13,13,0,0" multiline="false" name="re_username" width="227" height="30" valign="center" font="system_12" promptmode="true" prompttext="Search" promptcolor="gray" /><Button class="btn_session_edit" name="btn_session_add" margin="14,21,0,0" /></HBox><VListBox class="list" name="list_session" vscrollunit="100"></VListBox></VBox><!-- 默认提示 --><Control class="splitline_ver_level1" width="1" mouse="false" /><VBox name="box_default_tips" bkcolor="white" visible="false"><Control /><HBox height="20"><Control /><Label text="Select a chat start messaging" width="auto" /><Control /></HBox><Control /></VBox><!-- 聊天区域 --><TabBox name="tab_session_box" visible="true" bkcolor="white" selectedid="0"><VBox bkcolor="gray"></VBox><VBox bkcolor="pink"></VBox></TabBox></HBox></VBox>
</Window>

关键部分:

<!-- 好友列表 -->
<VListBox class="list" name="list_session" vscrollunit="100">
</VListBox>
<!-- 聊天区域 -->
<TabBox name="tab_session_box" visible="false" bkcolor="white" selectedid="1"><!-- 这里有2个预置的元素通过selectedid来控制谁显示,实际中VBox是动态创建并且填充进来的 --><!-- 注意,因为没有表头,搜索只能手动改selectedid的值,来看效果 --><VBox bkcolor="gray"></VBox><VBox bkcolor="pink"></VBox>
</TabBox>

步骤:

  1. 当左侧ListBox选中某一个Item时,显示TabBox。
  2. 我们通过字典 Map<std::string,ui::Box> 来判断某个会话是否曾经打开过。如果没有打开,则创建一个Box,加载到TabBox下且设置为当前选中项。否则,直接切换选中项即可。

selectedid=0时效果如下:
在这里插入图片描述
selectedid=1时效果如下:
在这里插入图片描述

会话列表实现

再介绍会话列表如何实现之前,先简单介绍一下ListBox控件。

ListBox

在 NimDuiLib 自带的例子 controls 工程中,ListBox是长这样的:
在这里插入图片描述

使用步骤如下:

  1. 在xml中先定义一个VListBox控件

    <VListBox class="list" name="list" padding="5,3,5,3">
    </VListBox>
    
  2. 然后再代码里面增加元素

    /* Initialize ListBox data */
    ui::ListBox* list = dynamic_cast<ui::ListBox*>(FindControl(L"list"));
    for (auto i = 0; i < 30; i++)
    {ui::ListContainerElement* element = new ui::ListContainerElement;element->SetText(nbase::StringPrintf(L"ListElement %d", i));// 这里可以设置元素的样式element->SetClass(L"listitem");element->SetFixedHeight(20);list->Add(element);
    }
    

我们看到,ListBox的元素其实时可以自定义样式的,那不就好办了?

自定义元素样式

NimDuiLib中,提供给了一个API,可以从指定XML创建控件的实例:

// 创建ListBox的元素
ui::ListContainerElement* item = new ui::ListContainerElement();
// 使用xml来填充元素,即:实现自定义控件
ui::GlobalManager::FillBoxWithCache(item, L"home_form/session_item.xml", nullptr);
// 添加进ListBox中
lb_session_->Add(item);

ui::GlobalManager::FillBoxWithCache() 这个API是我们实现自定义控件的关键所在,我们看一下这个xml的内容:

<?xml version="1.0" encoding="UTF-8"?>
<Window><ListContainerElement class="listitem" height="70" normalcolor="white"><HBox padding="5,0,10,0" childmargin="5" mouse="false"><!-- 会话名称 --><Label name="item_msg" singleline="false" endellipsis="true" width="stretch" margin="9,1,0,0" font="system_12" mouse="false" height="32" /></HBox></ListContainerElement>
</Window>

这个xml最顶级的节点是Window,然后接着必须是 ListContainerElement 代表这是一个ListBox元素的控件,我们看到里面可以自定义放自己的任何东西。假设里面有一个Label,我需要动态改变文本怎么办呢?我们可以使用 item->FindSubControl((L"item_msg") 来动态查找,然后调用其SetText() 函数设置文本即可。

完整实现

为了缩减篇幅,完整代码请移步 github

聊天界面实现

聊天界面的实现方式有2种主流方式:

  1. 通过内嵌浏览器(libcef),html+css来实现界面,通过C++控制逻辑,JS回调C++来实现交互。
  2. 通过原生界面实现,比如NimDuiLib。

第一种方式会相对占用内存一些,但是布局和调试很方便(TeamTalk中就是这样做的),在古老的Win32或者MFC时代,这样做可能会比较好。第二种方式是因为DirectUI(比如DuiLib)的出现,界面拥有更高的灵活度,故可能是现在比较常用的方式了吧,我们这里也主要是以介绍第二种方式为主

分析

在这里插入图片描述
因为每一行只能同时出现一个人的消息,所以我们也完全可以使用ListBox来实现(如上图)。每一个气泡,就是一个ListContainerElement,只是根据是否是自己发送的消息来动态决定显示在左侧还是右侧。

布局实现

右侧聊天消息界面布局如下:

<?xml version="1.0" encoding="UTF-8"?>
<Window><VBox bkcolor="white"><!-- 顶部标题栏 --><VBox height="51"><HBox height="50"><Control margin="10,2,0,0" bkimage="../public/headmask/icon_headimage_mask_50x50_normal.png" width="36" height="36" /><VBox height="42"><!-- 会话名字 --><Label name="lab_session_name" margin="7,3,0,0" text="testchannel" height="20" font="system_14" /><Label margin="7,2,0,0" text="36 members" height="17" font="system_12" /></VBox><Button name="btn_more" margin="0,14,9,0" normalimage="../session/icon_more_normal.png" width="24" height="24" /></HBox><Control class="splitline_hor_level1" mouse="false" /></VBox><!-- 内容区域 --><VListBox class="list" name="list_msg" vscrollunit="100"></VListBox><!-- 底部输入框 --><HBox height="50"><Button normalimage="../session/icon_file_normal.png" margin="10,7,0,7" width="36" height="36" /><VBox width="stretch"><Control /><RichEdit promptmode="true" prompttext="Broadcast a message…" promptcolor="gray" align="vcenter" vscrollbar="true" height="40" margin="0,2,0,2" /><Control /></VBox><Button normalimage="../session/icon_emotion_normal.png" margin="0,7,9,7" width="36" height="36" /></HBox></VBox>
</Window>

消息部分是使用的ListBox,针对ListContainerElement自定义元素的xml结构如下:

|-bubble_left.xml  # 左气泡,容器box|--text_left.xml   # 左消息气泡里面的内容,这个代表文本
|-bubble_right.xml # 右气泡,容器box|--text_right.xml  # 同理

bubble_left.xml 和 bubble_right.xml 是外层的气泡,text_left.xml 和 text_right.xml 是文本消息,将来可以增加表情、文件、图片等更多的内容。

bubble_left.xml内容示例:

<?xml version="1.0" encoding="UTF-8"?>
<Window><ListContainerElement class="listitem" height="auto"><HBox height="auto" margin="10,3,0,3"><!-- 左侧头像 --><Box name="header_panel" width="auto" height="auto" margin="0,5,0,0"></Box><VBox height="auto"><!-- 发送人名称 --><RichEdit name="sender_name" margin="6,0,0,0" text="bob" height="20" width="100" font="system_12" normaltextcolor="black" readonly="true" multiline="true" vscrollbar="false" autovscroll="false" /><HBox height="auto" margin="6,0,0,0"><!-- 气泡左角标 --><Control bkimage="file='../session/bubble_left.png'" width="auto" height="auto" margin="0,8,0,0"/><!-- 发送的内容,根据消息类型,动态渲染 --><Box name="BubbleBox" width="auto" height="auto"/></HBox></VBox></HBox></ListContainerElement>
</Window>

其中内置了一个 Box(BubbleBox) 来动态的创建气泡里面的内容,比如文本(text_left/right.xml),以后可能会有图片(image_left/right.xml),方便扩展。

text_left.xml示例内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<Window><Box bordersize="1" borderround="2,2" bkcolor="bk_msg_bubble_color" height="30" width="82" padding="8,8,7,7"><!-- 文本消息内容 --><RichEdit name="text" font="system_12" normaltextcolor="black" menu="true" readonly="true" multiline="true" vscrollbar="false" autovscroll="false" /></Box>
</Window>

使用时,可以对外提供一个函数,来新增一条消息,比如:

void SessionBox::AddMsg(const cim::MessageModel& msg) {if (msg.msg_type != kCIM_MSG_TYPE_TEXT) {LogInfo("unknown msg type");return;}// ListBox的元素ui::ListContainerElement* element = new ui::ListContainerElement();if (msg.IsSystemMsg()) {ui::GlobalManager::FillBoxWithCache(element, L"session/bubble_row.xml", nullptr);} else {// 根据是否是自己发送的消息,来动态加载左右布局if (msg.IsMyMsg()) {ui::GlobalManager::FillBoxWithCache(element, L"session/bubble_right.xml", nullptr);} else {ui::GlobalManager::FillBoxWithCache(element, L"session/bubble_left.xml", nullptr);}}// 找到气泡所在的Box,来动态创建具体的内容auto box = dynamic_cast<ui::Box*>(element->FindSubControl(L"BubbleBox"));assert(box != nullptr);if (box != nullptr) {switch (msg.msg_type) {// 文本消息,创建文本内容case kCIM_MSG_TYPE_TEXT: {// 用一个Box来显示ui::Box* subBox = new ui::Box();ui::GlobalManager::FillBoxWithCache(subBox, msg.IsMyMsg() ? L"session/text_right.xml" : L"session/text_left.xml");// 动态设置里面的文本,直接使用其FindSubControl()函数查找auto richEdit = dynamic_cast<ui::RichEdit*>(subBox->FindSubControl(L"text"));assert(richEdit != nullptr);if (richEdit != nullptr) {richEdit->SetText(nbase::UTF8ToUTF16(msg.msg_data));}box->Add(subBox);}break;default:break;}}// 加入,显示this->listbox_msg->Add(element);
}

完整代码

详细代码参考 github

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/37139.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

chatgpt赋能python:Python调用微信扫一扫:简单易懂的方法

Python调用微信扫一扫&#xff1a;简单易懂的方法 微信扫一扫已经成为生活中不可或缺的一部分&#xff0c;它的方便、快捷和安全性受到了许多人的青睐。但你是否曾想过&#xff0c;作为一名Python工程师&#xff0c;你可以用Python编写程序来调用微信扫一扫吗&#xff1f;本篇…

利用python实现微信好友分析(简单)

一、功能介绍 本文主要介绍利用网页端微信获取数据,实现个人微信好友数据的获取,并进行一些简单的数据分析&#xff0c;功能包括&#xff1a; 1.爬取好友列表,显示好友昵称、性别和地域和签名, 文件保存为 xlsx 格式 2.统计好友的地域分布&#xff0c;并且做成词云和可视化展…

自制聊天机器人实现与chatgpt或微信好友对话【附代码】

闲来无事&#xff0c;想实现一个可与chatgpt或者微信好友对话的聊天机器人。该聊天机器人还可应用于QQ好友或者其他地方的语音输入。功能还是比较简单的&#xff0c;后期会慢慢更新&#xff0c;让人机交互体验感不断提升。 项目描述&#xff1a; 语音输入"开启语音助手&…

C-Eval: 构造中文大模型的知识评估基准

作者&#xff1a;符尧&#xff0c;何俊贤 本项目由上海交通大学&#xff0c;清华大学&#xff0c;爱丁堡大学共同完成 立项于 2023 年 2 月 28 日 从 2023 年 4 月开始 Alpha - Beta 测试 发布于 2023 年 5 月 22 日本文约5800字&#xff0c;建议阅读10分钟这篇文章是把我们构造…

13948道题目,涵盖微积分、线代等52个学科,上交清华给中文大模型做了个测试集...

视学算法发布 作者&#xff1a;符尧、何俊贤 本项目由上海交通大学&#xff0c;清华大学&#xff0c;爱丁堡大学共同完成。 ChatGPT 的出现&#xff0c;使中文社区意识到与国际领先水平的差距。近期&#xff0c;中文大模型研发如火如荼&#xff0c;但中文评价基准却很少。 在 O…

上交清华提出中文大模型的知识评估基准C-Eval,辅助模型开发而非打榜

深度学习自然语言处理 分享 作者&#xff1a;符尧、何俊贤 ChatGPT 的出现&#xff0c;使中文社区意识到与国际领先水平的差距。近期&#xff0c;中文大模型研发如火如荼&#xff0c;但中文评价基准却很少。在 OpenAI GPT 系列 / Google PaLM 系列 / DeepMind Chinchilla 系列 …

GPT-3是精神病患者吗?从心理学角度评估大型语言模型

原文链接&#xff1a;https://www.techbeat.net/article-info?id4494 作者&#xff1a;seven_ 20世纪60年代&#xff0c;麻省理工学院人工智能实验室的Joseph Weizenbaum编写了第一个自然语言处理&#xff08;NLP&#xff09;聊天机器人ELIZA[1]&#xff0c;ELIZA通过使用模式…

大模型能否通过图灵测试呢,AI21 Labs做了一个百万级在线游戏《human or not》

论文链接&#xff1a; https://arxiv.org/abs/2305.20010项目地址&#xff1a;https://www.humanornot.ai/ “我相信&#xff0c;在今后50年的时间里&#xff0c;计算机有可能会展现出更出色的能力&#xff0c;以至于普通测试者在5分钟的提问后区分出机器和人的可能性不会超过7…

nodejs 框架选型express koa egg midwayjs nestjs 对比

最近要做个开源项目&#xff0c;又要写node 工程&#xff0c;之前用的是koa 框架&#xff0c;最近看到了nestjs egg midwayjs 等框架一时间难以抉择。 人工智能的答案 文心一言 midwayjs 还写错了&#xff0c;感觉的很少&#xff0c;最后总结等于白说各有千秋。 chatgpt 好…

微信HOOK+协议 协同开发 微信直播 视频号场控

近期&#xff0c;很多微信直播场控的功能软件出现 和朋友聊了一下&#xff0c;主要功能是通过PC微信的接口实现的 但是部分功能是PC接口没有的 因此需要通过PB组协议包&#xff0c;然后利用PC的HOOK接口&#xff0c;进行执行 PB组包 pb.empty () pb.setBin (“1”, { }) pb.…

如何搭建一对一直播PHP直播系统源码的流程

首先准备一套完整的PHP直播系统源码&#xff0c;服务器&#xff08;Linux系统&#xff09;、一对一直播PHP直播平台源码大多采用云服务器&#xff0c;不仅速度快、效率高&#xff0c;相对于物理服务器来说也更加安全&#xff0c;并且开发成本低&#xff0c;费用少&#xff0c;保…

本地直播平台的搭建—四种方式

本地直播平台的搭建 方法一&#xff1a;Windows下用FFmpegnginxrtmp搭建直播环境 实现推流、拉流 &#xff08;测试通过&#xff09;环境1. 简介&#xff1a;2. 准备文件3. 启动nginx服务器4. 配置FFmpeg5.运行 方法二&#xff1a;打开两个VLC&#xff0c;一个作为推流&#xf…

直播系统解决方案-搭建你自己的直播平台

背景 当下&#xff0c;视频直播行业在中国逐渐走红。在刚刚过去的2015年&#xff0c;视频直播成为互联网行业最抢眼的领域之一。从游戏到秀场&#xff0c;从传统的网页端到移动互联网&#xff0c;各大直播平台包括斗鱼、熊猫tv、虎牙战旗还有纯移动端的印客、易直播等&#xff…

搭建直播带货平台,实现直播间的即时聊天

如今直播火的简直不像样子了。在直播间里会有观众和主播交流的功能。主要方式是主播动口&#xff08;说&#xff09;&#xff0c;观众动手&#xff08;打字&#xff09;。这篇文章讲解一下搭建直播带货平台聊天功能的实现。这里为了更清楚的看到效果功能&#xff0c;我做了一个…

内网直播(局域网直播)系统的搭建

搭建一套完全本地化部署的流媒体直播点播系统&#xff0c;引入本地演播室&#xff0c;录播&#xff0c;报告厅、会议&#xff0c;电视节目等实时信号&#xff0c;实现本地网络的手机、PC、机顶盒等智能终端进行观看。系统集成直播&#xff0c;点播&#xff0c;录制&#xff0c;…

直播平台搭建

一、直播系统架构介绍 1. 直播产品的种类&#xff1a; 泛娱乐直播 例如&#xff1a;花椒、映客等娱乐直播&#xff0c;斗鱼、熊猫等游戏直播实时互动直播 例如&#xff1a;音视频会议、教育直播等&#xff0c;像Zoom、声网 二、搭建流媒体服务 准备流媒体服务器&#xff0…

手把手教你直播平台怎么搭建

手把手教你直播平台怎么搭建 后端项目初始化 1.全局安装express脚手架 额&#xff0c;这个应该是属于准备工作的。给忘记了&#xff0c;那就凑合放在这里吧&#xff0c;别打我&#xff0c;我知道错了&#xff0c;但我就是不改【狗头保命】 cnpm install -g express-generat…

【AI】在线网站随机生成假头像、不同头像

搜集到的一些科技前沿有趣的网站。 目前能想到的用途是不侵犯他人肖像权的情况下做些假数据&#xff0c;展示性的数据。每次刷新ai都会随机生成一张头像。 真人头像&#xff0c;欧美偏多&#xff0c;亚洲面孔少&#xff1a;https://thispersondoesnotexist.com/ 二次元女生头…

Android:使用LayerDrawable动态生成四宫格头像(包含双人、三人头像)

其实用自定义View也可以实现&#xff0c;我比较懒&#xff0c;就用LayerDrawable来创建一个新的Drawable资源实现。 举例4宫格&#xff0c;9宫格原理类似&#xff0c;每个图标的位置需要用边距慢慢调成预期的效果 效果如下&#xff1a; 双人头像&#xff1a; 三人头像&#x…

深度分析:用户最喜欢用哪种NFT做头像

自 CryptoPunks 作为首支蓝筹 NFT 项目被人们关注以来&#xff0c;关于 NFT 可以做什么的讨论便一直没有停歇&#xff0c;各类 NFT 创新应用也是层出不穷。除了头像以外&#xff0c;收藏、艺术、游戏、社交、运动等领域都可以看到 NFT 的身影。不过无论是从项目数量还是应用广度…