cocos2dx-3.10 聊天系统实现(C++实现)

来源:互联网 发布:数据监控系统毕业设计 编辑:程序博客网 时间:2024/06/04 23:35

cocos2dx-3.10  聊天系统实现(C++实现)

1.版权声明

    转载请注明出处:http://write.blog.csdn.net/postedit/51910754


2.前言

      一直忙着,没空写,趁中秋有点空,就码上奋斗

      本期介绍聊天系统制作,使用ListView和RichText 完成,本期重点是官方富文本RickText类的修改

       附上效果图:

        

3.内容

      介绍RichText的修改,由于官方的RickText 不支持描边、下划线、超链接,这里面将对官方RichText进行改造:
       因为用的是官方的预编译库,没有cpp源码,再就是为了不影响源码,就新建了自己的RichUI类。
      首先新建RichUI.h头文件,找到官方的UIRichText.h,拷贝内容至刚新建的RichUI.h头文件中,修改其中几处内容:
      将namespace ui改下,避免和官方冲突,主要做的修改的在RichElementText里,这里贴上我修改好的:
      
#ifndef __RICHUI_H__#define __RICHUI_H__#include "ui/UIWidget.h"#include "cocos2d.h"USING_NS_CC;NS_CC_BEGIN/*** @addtogroup cui* @modify source code by iuoon@zhejiang.china*/namespace cui {/***@brief Rich text element base class.* It defines the basic common properties for all rich text element.*/class  RichElement : public Ref{public:/***@brief Rich element type.*/enum class Type{TEXT,IMAGE,CUSTOM,NEWLINE};/*** @brief Default constructor.* @js ctor* @lua new*/RichElement() {};/*** @brief Default destructor.* @js NA* @lua NA*/virtual ~RichElement() {};/*** @brief Initialize a rich element with different arguments.** @param tag A integer tag value.* @param color A color in @see `Color3B`.* @param opacity A opacity value in `GLubyte`.* @return True if initialize success, false otherwise.*/bool init(int tag, const Color3B& color, GLubyte opacity);protected:Type _type;int _tag;CC_SYNTHESIZE(std::string, _pramas, Pramas);Color3B _color;GLubyte _opacity;friend class RichText;};/***@brief Rich element for displaying text.*/class  RichElementText : public RichElement{public:/***@brief Default constructor.* @js ctor* @lua new*/RichElementText() { _type = Type::TEXT;_outLine = -1;_outLineColor = Color4B::BLACK;_shadow = false;_linkurl = "";_underLinecolor = Color4B(0, 0, 0, 0);_underLinesize = -1;_touchCallback = nullptr;};/***@brief Default destructor.* @js NA* @lua NA*/virtual ~RichElementText() {};/*** @brief Initialize a RichElementText with various arguments.** @param tag A integer tag value.* @param color A color in Color3B.* @param opacity A opacity in GLubyte.* @param text Content string.* @param fontName Content font name.* @param fontSize Content font size.* @return True if initialize scucess, false otherwise.*/bool init(int tag, const Color3B& color, GLubyte opacity, const std::string& text, const std::string& fontName, float fontSize);/*** @brief Create a RichElementText with various arguments.** @param tag A integer tag value.* @param color A color in Color3B.* @param opacity A opacity in GLubyte.* @param text Content string.* @param fontName Content font name.* @param fontSize Content font size.* @return RichElementText instance.*/static RichElementText* create(int tag, const Color3B& color, GLubyte opacity, const std::string& text, const std::string& fontName, float fontSize);void setTouchCallBack(std::function<void(std::string)> touch, std::string tag);void setLinkUrl(std::string linkurl);protected:std::string _text;std::string _fontName;float _fontSize;friend class RichText;/**************************************/protected://CC_SYNTHESIZE(Color4B, _textColor, TextColor); //设置字体颜色CC_SYNTHESIZE(int, _outLine, OutLine);  //描边大小CC_SYNTHESIZE(Color4B, _outLineColor, OutLineColor);//描边颜色CC_SYNTHESIZE(bool, _shadow, Shadow); //启用阴影CC_SYNTHESIZE_READONLY(std::string, _linkurl, LinkUrl);//设置链接(或点击事件当参数传输)CC_SYNTHESIZE(Color4B, _underLinecolor, UnderLineColor);//下划线颜色CC_SYNTHESIZE(int, _underLinesize, UnderLineSize); //下划线大小CC_SYNTHESIZE_READONLY(std::function<void(std::string)>, _touchCallback, TouchCallBack);//点击回调函数private:void linkCallback(std::string str);};/***@brief Rich element for displaying images.*/class  RichElementImage : public RichElement{public:/*** @brief Default constructor.* @js ctor* @lua new**/RichElementImage() { _type = Type::IMAGE; };/*** @brief Default destructor.* @js NA* @lua NA*/virtual ~RichElementImage() {};/*** @brief Initialize a RichElementImage with various arguments.** @param tag A integer tag value.* @param color A color in Color3B.* @param opacity A opacity in GLubyte.* @param filePath A image file name.* @return True if initialize success, false otherwise.*/bool init(int tag, const Color3B& color, GLubyte opacity, const std::string& filePath);/*** @brief Create a RichElementImage with various arguments.** @param tag A integer tag value.* @param color A color in Color3B.* @param opacity A opacity in GLubyte.* @param filePath A image file name.* @return A RichElementImage instance.*/static RichElementImage* create(int tag, const Color3B& color, GLubyte opacity, const std::string& filePath);protected:std::string _filePath;Rect _textureRect;int _textureType;friend class RichText;};/***@brief Rich element for displaying custom node type.*/class  RichElementCustomNode : public RichElement{public:/*** @brief Default constructor.* @js ctor* @lua new*/RichElementCustomNode() { _type = Type::CUSTOM; };/*** @brief Default destructor.* @js NA* @lua NA*/virtual ~RichElementCustomNode() { CC_SAFE_RELEASE(_customNode); };/*** @brief Initialize a RichElementCustomNode with various arguments.** @param tag A integer tag value.* @param color A color in Color3B.* @param opacity A opacity in GLubyte.* @param customNode A custom node pointer.* @return True if initialize success, false otherwise.*/bool init(int tag, const Color3B& color, GLubyte opacity, Node* customNode);/*** @brief Create a RichElementCustomNode with various arguments.** @param tag A integer tag value.* @param color A color in Color3B.* @param opacity A opacity in GLubyte.* @param customNode A custom node pointer.* @return A RichElementCustomNode instance.*/static RichElementCustomNode* create(int tag, const Color3B& color, GLubyte opacity, Node* customNode);protected:Node* _customNode;friend class RichText;};/***@brief Rich element for new line.*/class  RichElementNewLine : public RichElement{public:/*** @brief Default constructor.* @js ctor* @lua new**/RichElementNewLine() { _type = Type::NEWLINE; };/*** @brief Default destructor.* @js NA* @lua NA*/virtual ~RichElementNewLine() {};/*** @brief Create a RichElementNewLine with various arguments.** @param tag A integer tag value.* @param color A color in Color3B.* @param opacity A opacity in GLubyte.* @return A RichElementNewLine instance.*/static RichElementNewLine* create(int tag, const Color3B& color, GLubyte opacity);protected:friend class RichText;};/***@brief A container for displaying various RichElements.* We could use it to display texts with images easily.*/class  RichText : public ui::Widget{public:/*** @brief Default constructor.* @js ctor* @lua new*/RichText();/*** @brief Default destructor.* @js NA* @lua NA*/virtual ~RichText();/*** @brief Create a empty RichText.** @return RichText instance.*/static RichText* create();/*** @brief Insert a RichElement at a given index.** @param element A RichElement type.* @param index A given index.*/void insertElement(RichElement* element, int index);/*** @brief Add a RichElement at the end of RichText.** @param element A RichElement instance.*/void pushBackElement(RichElement* element);/*** @brief Remove a RichElement at a given index.** @param index A integer index value.*/void removeElement(int index);/*** @brief Remove specific RichElement.** @param element A RichElement type.*/void removeElement(RichElement* element);/*** @brief Set vertical space between each RichElement.** @param space Point in float.*/void setVerticalSpace(float space);/*** @brief Rearrange all RichElement in the RichText.* It's usually called internally.*/void formatText();virtual void visit(Renderer* renderer, const Mat4 &parentTransform, uint32_t parentFlags) override;//override functions.virtual void ignoreContentAdaptWithSize(bool ignore) override;virtual std::string getDescription() const override;CC_CONSTRUCTOR_ACCESS:virtual bool init() override;virtual void onEnter() override;virtual void onExit() override;protected:virtual void adaptRenderers() override;virtual void initRenderer() override;void pushToContainer(Node* renderer);void handleTextRenderer(const RichElementText& textInfo);//void handleTextRenderer(const std::string& text, const std::string& fontName, float fontSize, const Color3B& color, GLubyte opacity);void handleImageRenderer(const std::string& fileParh, const Color3B& color, GLubyte opacity);void handleCustomRenderer(Node* renderer);void formarRenderers();void addNewLine();bool onTouchBegan(Touch *touch, Event *unusedEvent);void onTouchEnded(Touch *touch, Event *unusedEvent);CC_SYNTHESIZE(int, _touchPriority, TouchPriority);protected:bool _formatTextDirty;Vector<RichElement*> _richElements;std::vector<Vector<Node*>*> _elementRenders;std::map<Node*, std::function<void(std::string)> > _touchDelegate;//定义node对应的事件float _leftSpaceWidth;float _verticalSpace;};}NS_CC_END#endif /* defined(__RICHUI_H__) */



      同样新建RichUI.cpp文件,将UIRichText.cpp中的源码拷贝至RichUI.cpp文件中,修改部分代码日下:
#include "ui/RichUI.h"#include "ui/UIHelper.h"NS_CC_BEGINnamespace cui {bool RichElement::init(int tag, const Color3B &color, GLubyte opacity){_tag = tag;_color = color;_opacity = opacity;return true;}RichElementText* RichElementText::create(int tag, const Color3B &color, GLubyte opacity, const std::string& text, const std::string& fontName, float fontSize){RichElementText* element = new (std::nothrow) RichElementText();if (element && element->init(tag, color, opacity, text, fontName, fontSize)){element->autorelease();return element;}CC_SAFE_DELETE(element);return nullptr;}bool RichElementText::init(int tag, const Color3B &color, GLubyte opacity, const std::string& text, const std::string& fontName, float fontSize){if (RichElement::init(tag, color, opacity)){_text = text;_fontName = fontName;_fontSize = fontSize;return true;}return false;}void RichElementText::setTouchCallBack(std::function<void(std::string)> touch, std::string pramas){_touchCallback = touch;_pramas = pramas;}void RichElementText::setLinkUrl(std::string linkurl){_linkurl = linkurl;setTouchCallBack(std::bind(&RichElementText::linkCallback, this, std::placeholders::_1), linkurl);}void RichElementText::linkCallback(std::string str){log("call open url %s", str.c_str());}RichElementImage* RichElementImage::create(int tag, const Color3B &color, GLubyte opacity, const std::string& filePath){RichElementImage* element = new (std::nothrow) RichElementImage();if (element && element->init(tag, color, opacity, filePath)){element->autorelease();return element;}CC_SAFE_DELETE(element);return nullptr;}bool RichElementImage::init(int tag, const Color3B &color, GLubyte opacity, const std::string& filePath){if (RichElement::init(tag, color, opacity)){_filePath = filePath;return true;}return false;}RichElementCustomNode* RichElementCustomNode::create(int tag, const Color3B &color, GLubyte opacity, cocos2d::Node *customNode){RichElementCustomNode* element = new (std::nothrow) RichElementCustomNode();if (element && element->init(tag, color, opacity, customNode)){element->autorelease();return element;}CC_SAFE_DELETE(element);return nullptr;}bool RichElementCustomNode::init(int tag, const Color3B &color, GLubyte opacity, cocos2d::Node *customNode){if (RichElement::init(tag, color, opacity)){_customNode = customNode;_customNode->retain();return true;}return false;}RichElementNewLine* RichElementNewLine::create(int tag, const Color3B& color, GLubyte opacity){RichElementNewLine* element = new (std::nothrow) RichElementNewLine();if (element && element->init(tag, color, opacity)){element->autorelease();return element;}CC_SAFE_DELETE(element);return nullptr;}RichText::RichText() :_formatTextDirty(true),_leftSpaceWidth(0.0f),_verticalSpace(0.0f),_touchPriority(-1){_touchDelegate.clear();}RichText::~RichText(){_richElements.clear();//std::map<Node*, std::function<void(std::string)> >::const_iterator it = _touchDelegate.begin();while (it != _touchDelegate.end()){Node* node = it->first;if (node->getUserData() != nullptr){delete (std::string*)(node->getUserData());node->setUserData(nullptr);}++it;}_touchDelegate.clear();}/***************可以重写改造换行******************/RichText* RichText::create(){RichText* widget = new (std::nothrow) RichText();if (widget && widget->init()){widget->autorelease();return widget;}CC_SAFE_DELETE(widget);return nullptr;}bool RichText::init(){if (Widget::init()){return true;}return false;}void RichText::onEnter(){Widget::onEnter();EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create();listener->setSwallowTouches(true);listener->onTouchBegan = CC_CALLBACK_2(RichText::onTouchBegan, this);listener->onTouchEnded = CC_CALLBACK_2(RichText::onTouchEnded, this);_eventDispatcher->addEventListenerWithFixedPriority(listener, _touchPriority);}void RichText::onExit(){Widget::onExit();_eventDispatcher->removeAllEventListeners();}void RichText::initRenderer(){}void RichText::insertElement(RichElement *element, int index){_richElements.insert(index, element);_formatTextDirty = true;}void RichText::pushBackElement(RichElement *element){_richElements.pushBack(element);_formatTextDirty = true;}void RichText::removeElement(int index){_richElements.erase(index);_formatTextDirty = true;}void RichText::removeElement(RichElement *element){_richElements.eraseObject(element);_formatTextDirty = true;}void RichText::formatText(){if (_formatTextDirty){this->removeAllProtectedChildren();_elementRenders.clear();if (_ignoreSize){addNewLine();for (ssize_t i = 0; i<_richElements.size(); i++){RichElement* element = _richElements.at(i);Node* elementRenderer = nullptr;switch (element->_type){case RichElement::Type::TEXT:{Label* elementLabel = nullptr;RichElementText* elmtText = static_cast<RichElementText*>(element);if (FileUtils::getInstance()->isFileExist(elmtText->_fontName)){elementLabel = Label::createWithTTF(elmtText->_text.c_str(), elmtText->_fontName, elmtText->_fontSize);}else{elementLabel = Label::createWithSystemFont(elmtText->_text.c_str(), elmtText->_fontName, elmtText->_fontSize);}if (elmtText->getOutLine() > 0){elementLabel->enableOutline(elmtText->getOutLineColor(), elmtText->getOutLine());}if (elmtText->getShadow()){elementLabel->enableShadow();}if (elmtText->getUnderLineSize() > 0){LayerColor* l = nullptr;if (elmtText->getUnderLineColor().a == 0){l = LayerColor::create(Color4B(elmtText->_color), elementLabel->getContentSize().width, elmtText->getUnderLineSize());}else{l = LayerColor::create(elmtText->getUnderLineColor(), elementLabel->getContentSize().width, elmtText->getUnderLineSize());}elementLabel->setUserObject(l);}if (elmtText->getTouchCallBack()){std::string* tag = new std::string(""+elmtText->getPramas());elementLabel->setUserData(tag);_touchDelegate[elementLabel] = elmtText->getTouchCallBack();}elementRenderer = elementLabel;break;}case RichElement::Type::IMAGE:{RichElementImage* elmtImage = static_cast<RichElementImage*>(element);elementRenderer = Sprite::create(elmtImage->_filePath.c_str());break;}case RichElement::Type::CUSTOM:{RichElementCustomNode* elmtCustom = static_cast<RichElementCustomNode*>(element);elementRenderer = elmtCustom->_customNode;break;}case RichElement::Type::NEWLINE:{addNewLine();break;}default:break;}elementRenderer->setColor(element->_color);elementRenderer->setOpacity(element->_opacity);pushToContainer(elementRenderer);}}else{addNewLine();for (ssize_t i = 0; i<_richElements.size(); i++){RichElement* element = static_cast<RichElement*>(_richElements.at(i));switch (element->_type){case RichElement::Type::TEXT:{RichElementText* elmtText = static_cast<RichElementText*>(element);handleTextRenderer(*elmtText);break;}case RichElement::Type::IMAGE:{RichElementImage* elmtImage = static_cast<RichElementImage*>(element);handleImageRenderer(elmtImage->_filePath.c_str(), elmtImage->_color, elmtImage->_opacity);break;}case RichElement::Type::CUSTOM:{RichElementCustomNode* elmtCustom = static_cast<RichElementCustomNode*>(element);handleCustomRenderer(elmtCustom->_customNode);break;}case RichElement::Type::NEWLINE:{addNewLine();break;}default:break;}}}formarRenderers();_formatTextDirty = false;}}void RichText::visit(Renderer * renderer, const Mat4 & parentTransform, uint32_t parentFlags){if (_enabled){formatText();Widget::visit(renderer, parentTransform, parentFlags);}}void RichText::handleTextRenderer(const RichElementText& textInfo){auto fileExist = FileUtils::getInstance()->isFileExist(textInfo._fontName);Label* textRenderer = nullptr;if (fileExist){textRenderer = Label::createWithTTF(textInfo._text, textInfo._fontName, textInfo._fontSize);}else{textRenderer = Label::createWithSystemFont(textInfo._text, textInfo._fontName, textInfo._fontSize);}float textRendererWidth = textRenderer->getContentSize().width;_leftSpaceWidth -= textRendererWidth;if (_leftSpaceWidth < 0.0f){float overstepPercent = (-_leftSpaceWidth) / textRendererWidth;std::string curText = textInfo._text;size_t stringLength = StringUtils::getCharacterCountInUTF8String(textInfo._text);int leftLength = stringLength * (1.0f - overstepPercent);// The adjustment of the new line positionauto originalLeftSpaceWidth = _leftSpaceWidth + textRendererWidth;auto leftStr = ui::Helper::getSubStringOfUTF8String(curText, 0, leftLength);textRenderer->setString(leftStr);auto leftWidth = textRenderer->getContentSize().width;if (originalLeftSpaceWidth < leftWidth) {// Have protrudingfor (;;) {leftLength--;leftStr = ui::Helper::getSubStringOfUTF8String(curText, 0, leftLength);textRenderer->setString(leftStr);leftWidth = textRenderer->getContentSize().width;if (leftWidth <= originalLeftSpaceWidth) {break;}else if (leftLength <= 0) {break;}}}else if (leftWidth < originalLeftSpaceWidth) {// A wide marginfor (;;) {leftLength++;leftStr = ui::Helper::getSubStringOfUTF8String(curText, 0, leftLength);textRenderer->setString(leftStr);leftWidth = textRenderer->getContentSize().width;if (originalLeftSpaceWidth < leftWidth) {leftLength--;break;}else if (stringLength <= leftLength) {break;}}}//The minimum cut length is 1, otherwise will cause the infinite loop.if (0 == leftLength) leftLength = 1;std::string leftWords = ui::Helper::getSubStringOfUTF8String(curText, 0, leftLength);std::string cutWords = ui::Helper::getSubStringOfUTF8String(curText, leftLength, stringLength - leftLength);if (leftLength > 0){Label* leftRenderer = nullptr;if (fileExist){leftRenderer = Label::createWithTTF(ui::Helper::getSubStringOfUTF8String(leftWords, 0, leftLength), textInfo._fontName, textInfo._fontSize);}else{leftRenderer = Label::createWithSystemFont(ui::Helper::getSubStringOfUTF8String(leftWords, 0, leftLength), textInfo._fontName, textInfo._fontSize);}if (leftRenderer){leftRenderer->setColor(textInfo._color);leftRenderer->setOpacity(textInfo._opacity);if (textInfo.getOutLine() > 0){leftRenderer->enableOutline(textInfo.getOutLineColor(), textInfo.getOutLine());}if (textInfo.getShadow()){leftRenderer->enableShadow();}if (textInfo.getUnderLineSize() > 0){LayerColor* l = nullptr;if (textInfo.getUnderLineColor().a == 0){l = LayerColor::create(Color4B(textInfo._color), leftRenderer->getContentSize().width, textInfo.getUnderLineSize());}else{l = LayerColor::create(textInfo.getUnderLineColor(), leftRenderer->getContentSize().width, textInfo.getUnderLineSize());}leftRenderer->setUserObject(l);}if (textInfo.getTouchCallBack()){std::string* tag = new std::string(textInfo.getPramas());leftRenderer->setUserData(tag);_touchDelegate[leftRenderer] = textInfo.getTouchCallBack();}pushToContainer(leftRenderer);}}addNewLine();RichElementText cutRich = textInfo;cutRich._text=cutWords;handleTextRenderer(cutRich);}else{textRenderer->setColor(textInfo._color);textRenderer->setOpacity(textInfo._opacity);if (textInfo.getOutLine() > 0){textRenderer->enableOutline(textInfo.getOutLineColor(), textInfo.getOutLine());}if (textInfo.getShadow()){textRenderer->enableShadow();}if (textInfo.getUnderLineSize() > 0){LayerColor* l = nullptr;if (textInfo.getUnderLineColor().a == 0){l = LayerColor::create(Color4B(textInfo._color), textRenderer->getContentSize().width, textInfo.getUnderLineSize());}else{l = LayerColor::create(textInfo.getUnderLineColor(), textRenderer->getContentSize().width, textInfo.getUnderLineSize());}textRenderer->setUserObject(l);}if (textInfo.getTouchCallBack()){std::string* tag = new std::string(textInfo.getPramas());textRenderer->setUserData(tag);_touchDelegate[textRenderer] = textInfo.getTouchCallBack();}pushToContainer(textRenderer);}}void RichText::handleImageRenderer(const std::string& fileParh, const Color3B &color, GLubyte opacity){Sprite* imageRenderer = Sprite::create(fileParh);handleCustomRenderer(imageRenderer);}void RichText::handleCustomRenderer(cocos2d::Node *renderer){Size imgSize = renderer->getContentSize();_leftSpaceWidth -= imgSize.width;if (_leftSpaceWidth < 0.0f){addNewLine();pushToContainer(renderer);_leftSpaceWidth -= imgSize.width;}else{pushToContainer(renderer);}}void RichText::addNewLine(){_leftSpaceWidth = _customSize.width;_elementRenders.push_back(new Vector<Node*>());}bool RichText::onTouchBegan(Touch * touch, Event * unusedEvent){std::map<Node*, std::function<void(std::string)> >::const_iterator it = _touchDelegate.begin();while (it != _touchDelegate.end()){Node* node = it->first;if (node->getBoundingBox().containsPoint(node->getParent()->convertTouchToNodeSpace(touch))){return true;}++it;}return false;}void RichText::onTouchEnded(Touch * touch, Event * unusedEvent){std::map<Node*, std::function<void(std::string)> >::const_iterator it = _touchDelegate.begin();while (it != _touchDelegate.end()){Node* node = it->first;if (node->getBoundingBox().containsPoint(node->getParent()->convertTouchToNodeSpace(touch))){if (node->getUserData() != nullptr){(it->second)(*((std::string*)node->getUserData()));}return;}++it;}}void RichText::formarRenderers(){if (_ignoreSize){float newContentSizeWidth = 0.0f;float newContentSizeHeight = 0.0f;Vector<Node*>* row = (_elementRenders[0]);float nextPosX = 0.0f;for (ssize_t j = 0; j<row->size(); j++){Node* l = row->at(j);l->setAnchorPoint(Vec2::ZERO);l->setPosition(nextPosX, 0.0f);this->addProtectedChild(l, 1);/****这里将下划线显示*************/Node* under = dynamic_cast<Node*>(l->getUserObject());if (under){under->setPosition(Point(nextPosX, -1));this->addProtectedChild(under,1);l->setUserObject(nullptr);}/**********************************/Size iSize = l->getContentSize();newContentSizeWidth += iSize.width;newContentSizeHeight = MAX(newContentSizeHeight, iSize.height);nextPosX += iSize.width;}this->setContentSize(Size(newContentSizeWidth, newContentSizeHeight));}else{float newContentSizeHeight = 0.0f;float *maxHeights = new float[_elementRenders.size()];for (size_t i = 0; i<_elementRenders.size(); i++){Vector<Node*>* row = (_elementRenders[i]);float maxHeight = 0.0f;for (ssize_t j = 0; j<row->size(); j++){Node* l = row->at(j);maxHeight = MAX(l->getContentSize().height, maxHeight);}maxHeights[i] = maxHeight;newContentSizeHeight += maxHeights[i];}float nextPosY = _customSize.height;for (size_t i = 0; i<_elementRenders.size(); i++){Vector<Node*>* row = (_elementRenders[i]);float nextPosX = 0.0f;nextPosY -= (maxHeights[i] + _verticalSpace);for (ssize_t j = 0; j<row->size(); j++){Node* l = row->at(j);l->setAnchorPoint(Vec2::ZERO);l->setPosition(nextPosX, nextPosY);this->addProtectedChild(l, 1);/****这里将下划线显示*************/Node* under = dynamic_cast<Node*>(l->getUserObject());if (under){under->setPosition(Point(nextPosX, nextPosY - 1));this->addProtectedChild(under,1);l->setUserObject(nullptr);}/**********************************/nextPosX += l->getContentSize().width;}}delete[] maxHeights;}size_t length = _elementRenders.size();for (size_t i = 0; i<length; i++){Vector<Node*>* l = _elementRenders[i];l->clear();delete l;}_elementRenders.clear();if (_ignoreSize){Size s = getVirtualRendererSize();this->setContentSize(s);}else{this->setContentSize(_customSize);}updateContentSizeWithTextureSize(_contentSize);}void RichText::adaptRenderers(){this->formatText();}void RichText::pushToContainer(cocos2d::Node *renderer){if (_elementRenders.size() <= 0){return;}_elementRenders[_elementRenders.size() - 1]->pushBack(renderer);}void RichText::setVerticalSpace(float space){_verticalSpace = space;}void RichText::ignoreContentAdaptWithSize(bool ignore){if (_ignoreSize != ignore){_formatTextDirty = true;Widget::ignoreContentAdaptWithSize(ignore);}}std::string RichText::getDescription() const{return "RichText";}}NS_CC_END

   到了接近成功的一半了,下面新建ChatUI,这里面需要注意的是,RichUI需要设置尺寸大小的,这里需要根据发送内容动态调整RichUI的尺寸大小,
  否则如果发送内容过长,我们的消息就会叠到一块了。
 
#pragma once#ifndef _CHAT_UI_H_#define _CHAT_UI_H_#include "cocos2d.h"#include <string.h>#include "ui/RichUI.h"USING_NS_CC;using namespace std;using namespace cocos2d::cui;class ChatUI :public cocos2d::Layer{public:ChatUI();~ChatUI();static cocos2d::Scene* createScene();virtual bool init();CREATE_FUNC(ChatUI);void initRichEdit();cui::RichText* getChatMsg(int channel, string roleName, string chatMsg, char* signs);private:cui::RichText* _richBugle;//喇叭};#endif

#include "ui/ChatUI.h"#include "util/FontChina.h"#include "ui/UIText.h"ChatUI::ChatUI(){}ChatUI::~ChatUI(){}cocos2d::Scene * ChatUI::createScene(){auto scene = Scene::create();auto layer = ChatUI::create();scene->addChild(layer);return scene;}bool ChatUI::init(){if (!Layer::init()){return false;}this->initRichEdit();return true;}void ChatUI::initRichEdit(){}cui::RichText* ChatUI::getChatMsg(int channel, string  roleName, string  chatMsg, char * signs){string chanStr = "【当前】";string siz = ":";int msglen = chatMsg.size() + siz.size()+ chanStr.size() + roleName.size();int s = msglen / 44;if (msglen%44>0){s += 1;}cui::RichText* _richChat = cui::RichText::create();_richChat->ignoreContentAdaptWithSize(false);if (s==1){_richChat->setContentSize(Size(268, 18 * s));}else {_richChat->setContentSize(Size(268, 15 * s+3));}RichElementText* res = new RichElementText();RichElementText* resrole = new RichElementText();if (channel==1){chanStr = "【世界】";res = RichElementText::create(1, Color3B::YELLOW, 255, FontChina::getStringUTF8(chanStr), "font/simkai.ttf", 15);}else if (channel == 2) {chanStr = "【地区】";res = RichElementText::create(1, Color3B::ORANGE, 255, FontChina::getStringUTF8(chanStr), "font/simkai.ttf", 15);}else if (channel == 3) {chanStr = "【系统】";res = RichElementText::create(1, Color3B::RED, 255, FontChina::getStringUTF8(chanStr), "font/simkai.ttf", 15);}else {res = RichElementText::create(1, Color3B::WHITE, 255, FontChina::getStringUTF8(chanStr), "font/simkai.ttf", 15);}resrole = RichElementText::create(1, Color3B::GREEN, 255, FontChina::getStringUTF8(roleName), "font/simkai.ttf", 15);resrole->setUnderLineSize(1);resrole->setUnderLineColor(Color4B::GREEN);auto fuhao= RichElementText::create(1, Color3B::BLACK, 255, FontChina::getStringUTF8(":"), "font/simkai.ttf", 15);auto re = RichElementText::create(1, Color3B(0, 255, 255), 255, chatMsg , "font/simkai.ttf", 15);_richChat->pushBackElement(res);_richChat->pushBackElement(resrole);if (channel != 3){_richChat->pushBackElement(fuhao);}_richChat->pushBackElement(re);RichElementNewLine* line = RichElementNewLine::create(1,Color3B::WHITE,255);_richChat->pushBackElement(line);return _richChat;}

新建MianScene,完成场景加载:
 
#ifndef _MAIN_SCENE_H_#define _MAIN_SCENE_H_#include "cocos2d.h"#include "ui/CocosGUI.h"//UI相关的头文件#include "cocostudio/CocoStudio.h"#include "ui/ChatUI.h"USING_NS_CC;class MainScene :public cocos2d::Layer{public:MainScene();~MainScene();static cocos2d::Scene* createScene();virtual bool init();CREATE_FUNC(MainScene);void sendChatMsg(Ref * pSender, ui::Widget::TouchEventType type);public:Node* _ui_node;ChatUI* _chat;ui::TextField* _textfield;ui::ListView* _listview;int index;cui::RichText* _text;};#endif

#include "scene/MainScene.h"#include "YijianScene.h"#include "util/FontChina.h"MainScene::MainScene(){index = 1;}MainScene::~MainScene(){}cocos2d::Scene * MainScene::createScene(){auto scene = Scene::create();auto layer = MainScene::create();scene->addChild(layer);return scene;}bool MainScene::init(){if (!Layer::init()){return false;}Size visibleSize = Director::getInstance()->getVisibleSize();Vec2 origin = Director::getInstance()->getVisibleOrigin();_ui_node = CSLoader::createNode("scene/UILayer.csb");this->addChild(_ui_node, 200,100);_listview = static_cast<ui::ListView*>(_ui_node->getChildByName("ListView_1"));_listview->setBright(true);auto enterbt = static_cast<ui::Button*>(_ui_node->getChildByName("Button_3"));enterbt->addTouchEventListener(CC_CALLBACK_2(MainScene::sendChatMsg, this));//从服务端获取角色所在地图,这里默认加载auto yjlayer = YijianScene::createScene();this->addChild(yjlayer, 1,200);_chat = ChatUI::create();_text = _chat->getChatMsg(3, "", FontChina::getStringUTF8("欢迎【醉不忆情丝】上线,登陆IP地址:192.168.1.118"), "");_listview->insertCustomItem(_text, 0);return true;}void MainScene::sendChatMsg(Ref * pSender, ui::Widget::TouchEventType type){switch (type){case cocos2d::ui::Widget::TouchEventType::BEGAN:break;case cocos2d::ui::Widget::TouchEventType::MOVED:break;case cocos2d::ui::Widget::TouchEventType::ENDED:{_textfield = static_cast<ui::TextField*>(_ui_node->getChildByName("TextField_1"));if (_textfield->getString().compare("")!=0){_text = _chat->getChatMsg(0, "醉不忆情丝", _textfield->getString(), "");_listview->insertCustomItem(_text,index);_listview->sortAllChildren();_listview->jumpToBottom();//将最后显示在底部log("send message");index += 1;}break;}case cocos2d::ui::Widget::TouchEventType::CANCELED:break;default:break;}}

 就这样,聊天初步完成。

 未完待续。
      

0 0