您的位置:首页 > 移动开发 > Cocos引擎

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

2016-07-14 16:45 639 查看

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_BEGIN

namespace 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 position
auto originalLeftSpaceWidth = _leftSpaceWidth + textRendererWidth;
auto leftStr = ui::Helper::getSubStringOfUTF8String(curText, 0, leftLength);
textRenderer->setString(leftStr);
auto leftWidth = textRenderer->getContentSize().width;
if (originalLeftSpaceWidth < leftWidth) {
// Have protruding
for (;;) {
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 margin
for (;;) {
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;
}
}


 就这样,聊天初步完成。

 未完待续。
      
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: