作者:HU
转载请注明,原文链接:http://www.cnblogs.com/xioapingguo/p/4037414.html
虽然自从cocos2d-x更新到3.0后,使用freetype,并且增加了丰富文本,但这些文本都需要自己去设置,用起来也不方便,所以动手写了个简单html富文本
可以使用
class="p1"> <size=15></size>//字体大小
<fontname=“Arial”></fontname>//字体,这里必须有这个字体才能使用
<outline=2 color = 0xFFFFFFFF></outline>//描边
<shadow></shadow>//阴影
<link=“”></link>//链接
<img=“”>//图片
<color=0XFFFFFFFF></color>//文字颜色
<u=0xFF000000></u>//下划线
如“<fontname= \"Arial\" ><shadow>11111</shadow></fontname><u><link=\"www.baidu.com\">abc</link></u><img=\"CloseSelected.png\"><color = 0xFF><size=50>defg</color><outline=2 color=0xFF0000FF>hijk</outline></size>”效果:
因为兼容了系统UIRichText的功能,所以直接把UIRichText替换了
下面是头文件UIRichText.h
#ifndef __UIRICHTEXT_H__ #define __UIRICHTEXT_H__ #include "ui/UIWidget.h" NS_CC_BEGIN /* <size=15></size> <fontname=“Arial”></fontname> <outline=2 color = 0xFFFFFFFF></outline> <shadow></shadow> <link=“”></link> <img=“”> <color=0XFFFFFFFF></color> <u=0xFF000000></u> */ namespace ui { class RichElement : public Ref { public: enum class Type { TEXT, IMAGE, CUSTOM }; RichElement(){}; virtual ~RichElement(){}; protected: Type _type; CC_SYNTHESIZE(std::string,_tag,Tag); friend class RichText; }; class RichElementText : public RichElement { public: RichElementText() { _type = Type::TEXT; _color = Color3B::WHITE; _opacity = 255; _text = ""; _fontSize = 0; _fontName = ""; _textColor = Color4B::WHITE; _outLine = -1; _outLineColor = Color4B::BLACK; _shadow = false; _linkurl = ""; _underLinecolor = Color4B(0,0,0,0); _underLinesize = -1; _touchCallback = nullptr; } virtual ~RichElementText(){}; bool init(const std::string& text, const std::string& fontFile, float fontSize); static RichElementText* create(const std::string& text, const std::string& fontFile, float fontSize); void setTouchCallBack(std::function<void (std::string)> touch,std::string tag); void setLinkUrl(std::string linkurl); protected: CC_SYNTHESIZE(Color3B,_color,Color); CC_SYNTHESIZE(GLubyte,_opacity,Opacity); CC_SYNTHESIZE(std::string,_text,Text); CC_SYNTHESIZE(std::string,_fontName,FontName); CC_SYNTHESIZE(float,_fontSize,FontSize); 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); //std::function<void (std::string)> _touchCallback; friend class RichText; private: void linkCallback(std::string str); }; class RichElementImage : public RichElement { public: RichElementImage() { _type = Type::IMAGE; _tag = -1; _color = Color3B::WHITE; _opacity = 255; } virtual ~RichElementImage(){}; bool init(const std::string& filePath); static RichElementImage* create(const std::string& filePath); protected: CC_SYNTHESIZE(Color3B,_color,Color); CC_SYNTHESIZE(GLubyte,_opacity,Opacity); std::string _filePath; Rect _textureRect; int _textureType; friend class RichText; }; class RichElementCustomNode : public RichElement { public: RichElementCustomNode() { _type = Type::CUSTOM; _customNode = nullptr; }; virtual ~RichElementCustomNode() { CC_SAFE_RELEASE(_customNode); }; bool init(Node* customNode); static RichElementCustomNode* create(Node* customNode); protected: CC_SYNTHESIZE(Color3B,_color,Color); CC_SYNTHESIZE(GLubyte,_opacity,Opacity); Node* _customNode; friend class RichText; }; class RichText : public Widget { public: RichText(); virtual ~RichText(); static RichText* create(); static RichText* create(std::string str,const std::string& fontFile, float fontSize,const Size& size); bool initWithStr(std::string str,const std::string& fontFile, float fontSize,const Size& size); void insertElement(RichElement* element, int index); void pushBackElement(RichElement* element); void removeElement(int index); void removeElement(RichElement* element); virtual void visit(Renderer* renderer, const kmMat4 &parentTransform, bool parentTransformUpdated) override; void setVerticalSpace(float space); virtual void setAnchorPoint(const Point& pt); virtual const Size& getVirtualRendererSize() const override; void formatText(); virtual void ignoreContentAdaptWithSize(bool ignore); virtual std::string getDescription() const override; CC_CONSTRUCTOR_ACCESS: virtual bool init() override; virtual void onEnter() override; virtual void onExit() override; protected: virtual void initRenderer(); 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; float _leftSpaceWidth; float _verticalSpace; Node* _elementRenderersContainer; private: static float _set_fontSize; static std::string _set_fontFile; static int _set_outline; static Color4B _set_outline_color; static bool _set_shadow; static std::string _set_link; static Color4B _set_textColor; static bool _set_underline; static Color4B _set_underline_color; RichElement* createWithSet(const std::string& text); }; } NS_CC_END #endif /* defined(__UIRichText__) */
下面是Cpp,UIRichText.cpp, 由于3.0对UTF8文本有点问题,下面有几个方法自己实现的,如果3.2下直接使用后面注释掉的就可以了。具体区别对照下原版本的UIRichText.cpp就可以了。
#include "UIRichText.h" NS_CC_BEGIN namespace ui { #define DEFAULT_OUTLINE -1 #define DEFAULT_OUTLINE_COLOR (Color4B(0, 0, 0, 0)) #define DEFAULT_COLOR Color4B::WHITE #define DEFAULT_UNDERLINE false #define DEFAULT_UNDERLINE_COLOR (Color4B(0, 0, 0, 0)) int RichText::_set_outline = DEFAULT_OUTLINE; Color4B RichText::_set_outline_color = DEFAULT_OUTLINE_COLOR; bool RichText::_set_shadow = false; bool RichText::_set_underline = DEFAULT_UNDERLINE; Color4B RichText::_set_underline_color = DEFAULT_UNDERLINE_COLOR; Color4B RichText::_set_textColor = DEFAULT_COLOR; std::string RichText::_set_fontFile; float RichText::_set_fontSize; std::string RichText::_set_link; static std::string utf8_substr(const std::string& str, unsigned long start, unsigned long leng) { if (leng==0) { return ""; } unsigned long c, i, ix, q, min=std::string::npos, max=std::string::npos; for (q=0, i=0, ix=str.length(); i < ix; i++, q++) { if (q==start) { min = i; } if (q <= start+leng || leng==std::string::npos) { max = i; } c = (unsigned char) str[i]; if (c<=127) i+=0; else if ((c & 0xE0) == 0xC0) i+=1; else if ((c & 0xF0) == 0xE0) i+=2; else if ((c & 0xF8) == 0xF0) i+=3; else return "";//invalid utf8 } if (q <= start+leng || leng == std::string::npos) { max = i; } if (min==std::string::npos || max==std::string::npos) { return ""; } return str.substr(min,max); } bool RichElementText::init(const std::string& text, const std::string& fontFile, float fontSize) { _text = text; _fontName = fontFile; _fontSize = fontSize; return true; } RichElementText* RichElementText::create(const std::string& text, const std::string& fontFile, float fontSize) { RichElementText* htmlElementText = new RichElementText(); if (htmlElementText && htmlElementText->init(text, fontFile, fontSize)) { htmlElementText->autorelease(); return htmlElementText; } CC_SAFE_DELETE(htmlElementText); return nullptr; } void RichElementText::setTouchCallBack(std::function<void (std::string)> touch,std::string tag) { _touchCallback = touch; _tag = tag; } void RichElementText::setLinkUrl(std::string linkurl) { _linkurl = linkurl; setTouchCallBack(std::bind(&RichElementText::linkCallback, this,std::placeholders::_1),linkurl); } void RichElementText::linkCallback(std::string str) { CCLOG("call open url %s",str.c_str()); } bool RichElementImage::init(const std::string& filePath) { _filePath = filePath; return true; } RichElementImage* RichElementImage::create(const std::string& filePath) { RichElementImage* htmlElementImage = new RichElementImage(); if (htmlElementImage && htmlElementImage->init(filePath)) { htmlElementImage->autorelease(); return htmlElementImage; } CC_SAFE_DELETE(htmlElementImage); return nullptr; } bool RichElementCustomNode::init(cocos2d::Node *customNode) { _customNode = customNode; _customNode->retain(); return true; } RichElementCustomNode* RichElementCustomNode::create(cocos2d::Node *customNode) { RichElementCustomNode* element = new RichElementCustomNode(); if (element && element->init(customNode)) { element->autorelease(); return element; } CC_SAFE_DELETE(element); return nullptr; } RichText::RichText(): _formatTextDirty(true), _leftSpaceWidth(0.0f), _verticalSpace(0.0f), _touchPriority(-1), _elementRenderersContainer(nullptr) { _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 RichText(); if (widget && widget->init()) { widget->autorelease(); return widget; } CC_SAFE_DELETE(widget); return nullptr; } RichText* RichText::create(std::string str,const std::string& fontFile, float fontSize,const Size& size) { RichText* widget = new RichText(); if (widget && widget->initWithStr(str,fontFile,fontSize,size)) { widget->autorelease(); return widget; } CC_SAFE_DELETE(widget); return nullptr; } bool RichText::init() { if (!Widget::init()) { return false; } return true; } static const char* keywords[] = {"size","fontname","outline","shadow","link","img","color","u"}; static Color4B int2ccc3(unsigned long color) { Color4B ret; ret.r = (color&0xffffffff)>>24; ret.g = (color&0xffffff)>>16; ret.b = (color&0xffff)>>8; ret.a = color&0xff; return ret; } RichElement* RichText::createWithSet(const std::string& text) { if (text.empty()) { Node* node = Node::create(); node->setContentSize(Size(getContentSize().width, 1)); return RichElementCustomNode::create(node); } RichElementText* ret = RichElementText::create(text, _set_fontFile, _set_fontSize); if (_set_outline>0) { ret->setOutLine(_set_outline); ret->setOutLineColor(_set_outline_color); } ret->setShadow(_set_shadow); if (!_set_link.empty()) { ret->setLinkUrl(_set_link); } CCLOG("%d,%d,%d,%d",_set_textColor.r,_set_textColor.g,_set_textColor.b,_set_textColor.a); ret->setTextColor(_set_textColor); if (_set_underline) { ret->setUnderLineSize(2); if (_set_underline_color.a == 0) { ret->setUnderLineColor(_set_textColor); } else { ret->setUnderLineColor(_set_underline_color); } } return ret; } bool RichText::initWithStr(std::string str,const std::string& fontFile, float fontSize,const Size& size) { if (!Widget::init()) { return false; } ignoreContentAdaptWithSize(false); //setContentSize(size); setSize(size); _set_fontSize = fontSize; _set_fontFile = fontFile; _set_textColor = DEFAULT_COLOR; std::string s = str; unsigned long posStart = 0; unsigned long posEnd = 0; while (posStart<s.length()) { bool isEnd = false; posEnd = s.find("<",posStart); if (posStart!=posEnd) { std::string tempStr = s.substr(posStart,posEnd-posStart); std::string::value_type pos = tempStr.find("\n"); if (pos!=std::string::npos) { std::string s1 = tempStr.substr(0,pos).c_str(); if (!s1.empty()) { pushBackElement(createWithSet(s1)); } pushBackElement(createWithSet("")); std::string s2 = tempStr.substr(pos+1).c_str(); if (!s2.empty()) { pushBackElement(createWithSet(s2)); } } else { CCLOG("%s",tempStr.c_str()); pushBackElement(createWithSet(tempStr)); } if (posEnd==std::string::npos) { break; } } posStart = posEnd+1; CCLOG("%c",s.at(posStart)); if (s.at(posStart)=='/') { isEnd = true; posStart++; } int keyIndex = 0; for (keyIndex=0; keyIndex<8; keyIndex++) { if(s.compare(posStart, strlen(keywords[keyIndex]), keywords[keyIndex])==0) { break; } } if (keyIndex<8) { switch (keyIndex) { case 0: { posEnd = s.find(">",posStart); if (isEnd) { CCLOG("size end"); _set_fontSize = fontSize; } else { posStart = s.find("=",posStart)+1; int size = atoi(s.substr(posStart,posEnd-posStart).c_str()); _set_fontSize = size; CCLOG("%d",size); } } break; case 1: { posEnd = s.find(">",posStart); if (isEnd) { _set_fontFile = fontFile; CCLOG("fontname end"); } else { posStart = s.find("=",posStart)+1; std::string temp = s.substr(posStart,posEnd-posStart); std::string::value_type p1,p2; p1 = temp.find("\"")+1; p2 = temp.find("\"",p1); std::string fontname = temp.substr(p1,p2-p1); _set_fontFile = fontname; CCLOG("fontname = %s",fontname.c_str()); } } break; case 2: { posEnd = s.find(">",posStart+1); if (isEnd) { CCLOG("outline end"); _set_outline = DEFAULT_OUTLINE; _set_outline_color = DEFAULT_OUTLINE_COLOR; } else { posStart = s.find("=",posStart)+1; std::string temp = s.substr(posStart,posEnd-posStart); int size = atoi(temp.c_str()); _set_outline = size; CCLOG("outline %d",size); unsigned long p1 = temp.find("="); if (p1!=std::string::npos) { Color4B c = int2ccc3(strtoul(temp.substr(p1+1).c_str(), NULL, 16)); _set_outline_color = c; CCLOG("outline color = %d,%d,%d,%d",c.r,c.g,c.b,c.a); } } } break; case 3: { posEnd = s.find(">",posStart); if (isEnd) { CCLOG("shadow end"); _set_shadow = false; } else { _set_shadow = true; CCLOG("shadow start"); } } break; case 4: { posEnd = s.find(">",posStart); if (isEnd) { _set_link = ""; CCLOG("link end"); } else { posStart = s.find("=",posStart)+1; std::string temp = s.substr(posStart,posEnd-posStart); std::string::value_type p1,p2; p1 = temp.find("\"")+1; p2 = temp.find("\"",p1); std::string linkstr = temp.substr(p1,p2-p1); _set_link = linkstr; CCLOG("link = %s",linkstr.c_str()); } } break; case 5: { posEnd = s.find(">",posStart); posStart = s.find("=",posStart)+1; std::string temp = s.substr(posStart,posEnd-posStart); std::string::value_type p1,p2; p1 = temp.find("\"")+1; p2 = temp.find("\"",p1); std::string img = temp.substr(p1,p2-p1); Sprite* s = Sprite::create(img); if (s) { pushBackElement(RichElementCustomNode::create(s)); } CCLOG("img = %s",img.c_str()); } break; case 6: { posEnd = s.find(">",posStart); if (isEnd) { _set_textColor = DEFAULT_COLOR; CCLOG("color end"); } else { posStart = s.find("=",posStart)+1; Color4B c = int2ccc3(strtoul(s.substr(posStart,posEnd-posStart).c_str(), NULL, 16)); _set_textColor = c; CCLOG("%d,%d,%d,%d",c.r,c.g,c.b,c.a); } } break; case 7: { posEnd = s.find(">",posStart); if (isEnd) { _set_underline = false; _set_underline_color = DEFAULT_UNDERLINE_COLOR; CCLOG("underline end"); } else { _set_underline = true; if (s.substr(posStart,posEnd-posStart).find("=")!=std::string::npos) { posStart = s.find("=",posStart)+1; Color4B c = int2ccc3(strtoul(s.substr(posStart,posEnd-posStart).c_str(), NULL, 16)); _set_underline_color = c; CCLOG("%d,%d,%d,%d",c.r,c.g,c.b,c.a); } else { CCLOG("underline no color"); } } } break; default: break; } } posStart = posEnd+1; } return true; } 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(); } 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::initRenderer() { _elementRenderersContainer = Node::create(); _elementRenderersContainer->setAnchorPoint(Point(0.5f, 0.5f)); addProtectedChild(_elementRenderersContainer, 0, -1); } 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) { _elementRenderersContainer->removeAllChildren(); _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(); } elementLabel->setTextColor(/*elmtText->getTextColor()*/Color4B::RED); if (elmtText->getUnderLineSize()>0) { LayerColor* l = nullptr; if (elmtText->getUnderLineColor().a == 0) { l = LayerColor::create(elmtText->getTextColor(), 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->getTag()); elementLabel->setUserData(tag); _touchDelegate[elementLabel] = elmtText->getTouchCallBack(); } elementRenderer = elementLabel; elementRenderer->setColor(elmtText->_color); elementRenderer->setOpacity(elmtText->_opacity); break; } case RichElement::Type::IMAGE: { RichElementImage* elmtImage = static_cast<RichElementImage*>(element); elementRenderer = Sprite::create(elmtImage->_filePath.c_str()); elementRenderer->setColor(elmtImage->_color); elementRenderer->setOpacity(elmtImage->_opacity); break; } case RichElement::Type::CUSTOM: { RichElementCustomNode* elmtCustom = static_cast<RichElementCustomNode*>(element); elementRenderer = elmtCustom->_customNode; elementRenderer->setColor(elmtCustom->_color); elementRenderer->setOpacity(elmtCustom->_opacity); break; } default: break; } 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; } default: break; } } } formarRenderers(); _formatTextDirty = false; } } #define UTF8_ASCII(byte) (((unsigned char)(byte)>=0x00)&&((unsigned char)(byte)<=0x7F)) #define UTF8_FIRST(byte) (((unsigned char)(byte)>=0xC0)&&((unsigned char)(byte)<=0xFD)) #define UTF8_OTHER(byte) (((unsigned char)(byte)>=0x80)&&((unsigned char)(byte)<=0xBF)) static int _calcCharCount(const char * pszText,int len) { char *p = 0; long count = 0; if (!pszText || len <= 0) { return 0; } for(p=(char*)pszText; p<pszText+len; p++) { if (UTF8_ASCII(*p) || (UTF8_FIRST(*p))) { count++; } } return count; } void RichText::handleTextRenderer(const RichElementText& textInfo) { auto fileExist = FileUtils::getInstance()->isFileExist(textInfo.getFontName()); Label* textRenderer = nullptr; if (fileExist) { textRenderer = Label::createWithTTF(textInfo.getText(), textInfo.getFontName(), textInfo.getFontSize()); } else { textRenderer = Label::createWithSystemFont(textInfo.getText(), textInfo.getFontName(), textInfo.getFontSize()); } if (textInfo.getOutLine()>0) { textRenderer->enableOutline(textInfo.getOutLineColor(),textInfo.getOutLine()); } if (textInfo.getShadow()) { textRenderer->enableShadow(); } float textRendererWidth = textRenderer->getContentSize().width; _leftSpaceWidth -= textRendererWidth; if (_leftSpaceWidth < 0.0f) { float overstepPercent = (-_leftSpaceWidth) / textRendererWidth; std::string curText = textInfo.getText(); size_t stringLength = _calcCharCount(textInfo.getText().c_str(),textInfo.getText().length());//StringUtils::getCharacterCountInUTF8String(textInfo.getText()); int leftLength = stringLength * (1.0f - overstepPercent); std::string leftWords = utf8_substr(curText,0,leftLength); std::string cutWords = utf8_substr(curText, leftLength, curText.length() - leftLength); if (leftLength > 0) { Label* leftRenderer = nullptr; if (fileExist) { leftRenderer = Label::createWithTTF(utf8_substr(leftWords, 0, leftLength), textInfo.getFontName(), textInfo.getFontSize()); } else { leftRenderer = Label::createWithSystemFont(utf8_substr(leftWords, 0, leftLength), textInfo.getFontName(), textInfo.getFontSize()); } if (leftRenderer) { leftRenderer->setColor(textInfo.getColor()); leftRenderer->setOpacity(textInfo.getOpacity()); if (textInfo.getOutLine()>0) { leftRenderer->enableOutline(textInfo.getOutLineColor(),textInfo.getOutLine()); } if (textInfo.getShadow()) { leftRenderer->enableShadow(); } leftRenderer->setTextColor(textInfo.getTextColor()); if (textInfo.getUnderLineSize()>0) { LayerColor* l = nullptr; if (textInfo.getUnderLineColor().a==0) { l = LayerColor::create(textInfo.getTextColor(), 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.getTag()); leftRenderer->setUserData(tag); _touchDelegate[leftRenderer] = textInfo.getTouchCallBack(); } pushToContainer(leftRenderer); } } addNewLine(); RichElementText cutRich = textInfo; cutRich.setText(cutWords); handleTextRenderer(cutRich); } else { textRenderer->setColor(textInfo.getColor()); textRenderer->setOpacity(textInfo.getOpacity()); if (textInfo.getOutLine()>0) { textRenderer->enableOutline(textInfo.getOutLineColor(),textInfo.getOutLine()); } if (textInfo.getShadow()) { textRenderer->enableShadow(); } textRenderer->setTextColor(textInfo.getTextColor()); if (textInfo.getUnderLineSize()>0) { LayerColor* l = nullptr; if (textInfo.getUnderLineColor().a==0) { l = LayerColor::create(textInfo.getTextColor(), 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.getTag()); 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); if (imageRenderer==nullptr) { return; } imageRenderer->setColor(color); imageRenderer->setOpacity(opacity); 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*>()); } 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(Point::ZERO); l->setPosition(Point(nextPosX, 0.0f)); _elementRenderersContainer->addChild(l, 1); Node* under = dynamic_cast<Node*>(l->getUserObject()); if (under) { under->setPosition(Point(nextPosX,-1)); _elementRenderersContainer->addChild(under); l->setUserObject(nullptr); } Size iSize = l->getContentSize(); newContentSizeWidth += iSize.width; newContentSizeHeight = MAX(newContentSizeHeight, iSize.height); nextPosX += iSize.width; } _elementRenderersContainer->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(Point::ZERO); l->setPosition(Point(nextPosX, nextPosY)); _elementRenderersContainer->addChild(l, 1); Node* under = dynamic_cast<Node*>(l->getUserObject()); if (under) { under->setPosition(Point(nextPosX,nextPosY-1)); _elementRenderersContainer->addChild(under); l->setUserObject(nullptr); } nextPosX += l->getContentSize().width; } } _elementRenderersContainer->setContentSize(_contentSize); 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); _elementRenderersContainer->setPosition(_contentSize.width / 2.0f, _contentSize.height / 2.0f); } void RichText::pushToContainer(cocos2d::Node *renderer) { if (_elementRenders.size() <= 0) { return; } _elementRenders[_elementRenders.size()-1]->pushBack(renderer); } void RichText::visit(Renderer* renderer, const kmMat4 &parentTransform, bool parentTransformUpdated) { if (_enabled) { formatText(); Widget::visit(renderer, parentTransform, parentTransformUpdated); } } void RichText::setVerticalSpace(float space) { _verticalSpace = space; } void RichText::setAnchorPoint(const Point& pt) { Widget::setAnchorPoint(pt); _elementRenderersContainer->setAnchorPoint(pt); } const Size& RichText::getVirtualRendererSize() const { return _elementRenderersContainer->getContentSize(); } void RichText::ignoreContentAdaptWithSize(bool ignore) { if (_ignoreSize != ignore) { _formatTextDirty = true; Widget::ignoreContentAdaptWithSize(ignore); } } std::string RichText::getDescription() const { return "RichText"; } } NS_CC_END
使用方法,上面的str
RichText* _richText = RichText::create(str, "fonts/Marker Felt.ttf", 30, Size(300, 300)); _richText->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y)); _richText->setLocalZOrder(10); addChild(_richText);