cocos2dx 富文本框,支持換行,支持表情(支持漢字截斷無亂碼)
小工在做了一個游戲聊天功能,里面用到插入表情的富文本和換行的問題;
先看效果,不是你要的效果,可return;(截圖由於:輸入的問題,未能輸入漢字)



實現方式;
定義一個layer,在layer上擺放文本,表情,按鈕,等控件,由此來形成一個多控件組成的一個富文本;
表情:仿照QQ,用的是【xy】這種方式來表示,如【00】,對應資源就是00.png
換行:就是是把超出指定寬度的內容回車,實現換行(主要是坐標x=起始位置)當然涉及到表情等,容易出問題;
例子
string m_sString = “待到山花爛漫時,他在花叢中笑【12】叢中笑【12】叢中笑【12】叢中笑【12】”;
下面偽代碼實現
處理string 得到string的真實個數長度,一個漢字,一個字母代表一個長度;
創建循環體,分別來遍歷沒一個漢字或者是字母+特殊字符等,遇到【就判斷是否是表情,如果是表情就添加表情,表情添加之前需要將表情之前的漢字等先排列上,表情排列后繼續,進行遍歷;
如果發現當前遍歷的內容所占的屏幕長度就進行換行。表情的長度=getContextSize().width 來獲取;
具體實現如代碼
void MessageItem::changeLine()
{
CCArray *array = getChildren();
for (int i=0; i<array->count(); i++) {
CCNode* node =(CCNode*) array->objectAtIndex(i);
node->setPositionY(m_iDefaultSize);
}
}
void MessageItem::showText(const ccColor3B cColor3B )
{
bool bDoubleLine=false;
int posX= 0;//讀取內容的長度小標
int iMsgEnd = 1;
int iMsgStart =1;
int width = m_iPannelWidth ;//顯示面板的寬度
std::string r="";
//按照一個漢字一個長度,一個字母或者是特殊符號一個長度,得到的長度;(這樣避免換行的時候漢字被分開,出現亂碼現象)
int iRealLength = Tools::getRealStringLength(m_TotalMsg);
CCLabelTTF* tempTextView = CCLabelTTF::create();
tempTextView->setFontName("Arial-BoldMT");
tempTextView->setFontSize(24);
while( (r= Tools::subString(m_TotalMsg,iMsgStart,iMsgEnd))!= "")
{
//先判斷當前讀取的字符內容是否是表情
if(r[r.length()-1]=='[')
{
std::string tmp = Tools::subString(m_TotalMsg,iMsgEnd,iMsgEnd+3);
if(tmp[3]==']'&&isNumber(tmp[1])&&isNumber(tmp[2]))//face
{
//表情前面若有內容的處理
if(iMsgEnd-iMsgStart>0)
{
CCLabelTTF* textView = CCLabelTTF::create();
textView->setFontName("Arial-BoldMT");
textView->setFontSize(24);
textView->setColor(cColor3B);
textView->setString(r.substr(0,r.length()-1).c_str());
textView->setPosition(ccp(m_LeftMsg_x+posX, 0));
textView->setAnchorPoint(ccp(0, 0));
posX+=textView->getContentSize().width;
this->addChild(textView);
}
//如果有表情的處理
char temp[10] = {0};
if(tmp[1]-'0' == 0)
{
sprintf(temp, "%d.png",tmp[2]-'0');
}
else
{
sprintf(temp, "%d%d.png",tmp[1]-'0',tmp[2]-'0');
}
bLineHaveFace = true;
CCSprite *sp = CCSprite::create(temp);
sp->setScaleX(0.6);
sp->setScaleY(0.6);
sp->setAnchorPoint(ccp(0, 0));
//如果最后表情在一行的最后的換行處理
if(sp->getContentSize().width+posX>width)
{
posX=0;
if (m_bLimitOneLine == true)
{
break;
}
changeLine();
bDoubleLine=true;
}
iMsgEnd+=4;
iMsgStart=iMsgEnd;
sp->setPosition(ccp(m_LeftMsg_x+posX, 0));
posX+=sp->getContentSize().width*0.6;
this->addChild(sp);
if(iMsgEnd>iRealLength)
{
break;
}
continue;
}
}
tempTextView->setString(r.c_str());
//如果讀取到都是無表情的內容,如下進行換行;
if(tempTextView->getContentSize().width+posX+24 >= width)
{
CCLabelTTF* textView = CCLabelTTF::create();
textView->setFontName("Arial-BoldMT");
textView->setFontSize(24);
textView->setColor(cColor3B);
textView->setString(r.c_str());
textView->setPosition(ccp(m_LeftMsg_x+posX, 0));
textView->setAnchorPoint(ccp(0, 0));
this->addChild(textView);
iMsgEnd++;
iMsgStart=iMsgEnd;
posX=0;
if(iMsgEnd>iRealLength)
{
break;
}
if (m_bLimitOneLine)
{
break;
}
changeLine();
bDoubleLine=true;
}
else
{
iMsgEnd++;
if(iMsgEnd>iRealLength)
{
CCLabelTTF* textView = CCLabelTTF::create();
textView->setFontName("Arial-BoldMT");
textView->setColor(cColor3B);
textView->setFontSize(24);
textView->setString(r.c_str());
textView->setPosition(ccp(m_LeftMsg_x+posX, 0));
textView->setAnchorPoint(ccp(0, 0));
this->addChild(textView);
break;
}
}
}
if(bDoubleLine)
{
setContentSize(CCSizeMake(width, m_iDefaultSize*2));
m_pTypeName->setPositionY(m_iDefaultSize);
m_pUserName->setPositionY(m_iDefaultSize);
}
else
{
setContentSize(CCSizeMake(width, m_iDefaultSize));
m_pTypeName->setPositionY(0);
m_pUserName->setPositionY(0);
}
}
// 截取字符,必滿亂碼的處理;
std::string Tools::subString(std::string str ,int start ,int end)
{
if(typeid(str)==typeid(string) && str.length()>0)
{
int len=str.length();
string tmp="";
//先把str里的漢字和英文分開
vector <string> dump;
int i=0;
while(i<len)
{
if (is_zh_ch(str.at(i))==1)
{
dump.push_back(str.substr(i,3));
i=i+3;
}
else
{
dump.push_back(str.substr(i,1));
i=i+1;
}
}
int iDumpSize = dump.size();
end=end>0?end:iDumpSize;
if(start<0||start>end)
return "";
for(i=start; i<=end; i++)
{
tmp+=dump[i-1];
}
return tmp;
}
else
{
printf("str is not string\n");
return "";
}
}
//獲取字符串的真實長度處理
int Tools::getRealStringLength(std::string str){
int i=0;
int len=str.length();
int r=0;
while(i<len)
{
if (is_zh_ch(str.at(i))==1)
{
r++;
i=i+3;
}
else
{
r++;
i=i+1;
}
}
return r;
}
如上基本上處理了一個富文本的基本操作,功能比較簡單,但是做起來比較容易出問題,像換行,插入表情,截取漢字這個三個問題
