首页 > 代码库 > cocos2d-x中,简单html富文本显示

cocos2d-x中,简单html富文本显示

作者:HU

转载请注明,原文链接:http://www.cnblogs.com/xioapingguo/p/4037414.html 

 

虽然自从cocos2d-x更新到3.0后,使用freetype,并且增加了丰富文本,但这些文本都需要自己去设置,用起来也不方便,所以动手写了个简单html富文本

可以使用

 <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_BEGINnamespace 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);

 

cocos2d-x中,简单html富文本显示