关于字符编码的知识,请参考前辈的博客:字符串和编码格式
这里使用的是cocos2dx的2.2.3版本,底层的RictText换行机制不能满足中文换行,需要改动。由于在3.x的版本已经优化了,而且以后的项目也会转到3.x的版本,所以这里只是做一个记录,对底层换行机制的思想做一个分析,仅供学习用。
RichText的换行原理:
以文本换行为例(图片同样的道理),先用一个不带换行的label,算出该label的总长度L,然后和程序设定的宽w比较,w<L则一行足以,否则按w在L中比例来截取原字符串,作为第一行,剩余部分递归处理。看代码:
- <spanstyle="font-size:14px;">voidRichText::handleTextRenderer(constchar*text,char*fontName,floatfontSize,153); font-weight:bold; background-color:inherit">constccColor3B&color,GLubyteopacity)
- {
-
- CCLabelTTF*textRenderer=CCLabelTTF::create(text,fontName,fontSize);
- /*不换行时的label宽度*/
- floattextRendererWidth=textRenderer->getContentSize().width;
- /*用设定的大小-label宽度*/
- _leftSpaceWidth-=textRendererWidth;
- if(_leftSpaceWidth<0.0f)
- /*需要换行,则需要按比例截取原字符串:先计算超出的宽度所占的比例*/
- floatoverstepPercent=(-_leftSpaceWidth)/textRendererWidth;
- std::stringcurText=text;
-
- intstringLength=curText.length();
- /*1-超出比例=当前(设定宽度所占比)来截取字符串*/
- intleftLength=stringLength*(1.0f-overstepPercent);
- /*使用stl标准库的string函数截取字串*/
- std::stringleftWords=curText.substr(0,leftLength);
- std::stringcutWords=curText.substr(leftLength,curText.length()-1);
- /*字符串不为空,则绘制第一行label*/
- if(leftLength>0)
- {
- CCLabelTTF*leftRenderer=CCLabelTTF::create(leftWords.substr(0,leftLength).c_str(),108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> leftRenderer->setColor(color);
- leftRenderer->setOpacity(opacity);
- pushToContainer(leftRenderer);
- }
-
- /*开启新的一行,并作递归处理*/
- addNewLine();
- handleTextRenderer(cutWords.c_str(),fontSize,color,opacity);
- }
- else
- textRenderer->setColor(color);
- textRenderer->setOpacity(opacity);
- pushToContainer(textRenderer);
- }</span>
这里的重点是截取字串的方式,自带的substr不能很好的处理多字节字符的截取,中文会出现乱码,所以用自己写的函数实现,这个函数在网上能找到,但仍然有问题,我做了一些修改,将原来的substr改为自定义的“utf8_substr”函数:
<spanstyle="font-size:14px;">
- *str:原字符串
- *start:截串的起始位置(起始位置未必准确,通过判断调整)
- *leng:截取的长度(同样长度未必准确)
- */
- staticstd::stringutf8_substr(conststd::string&str,unsignedlongstart,87); font-weight:bold; background-color:inherit">longleng)
- if(leng==0)
- return"";
- unsignedlongc,i,strLen,minIdx=std::string::npos,actualLength=std::string::npos;
- //有效(不乱码)的起始位置和有效原的截取长度与参数有偏移差
- longstartOffset,lenOffset;
- for(i=0,strLen=str.length();i<=strLen;i++)
- //i按照字符所占的字节数做跳转的,utf-8中文字符时i的值0369.....
- if(i<=start)
- minIdx=i;
- startOffset=start-minIdx;
- if(i<=start+leng)
- lenOffset=start+leng-i;
- actualLength=leng+abs(startOffset)-abs(lenOffset);
- /*于所有字符的编码表中的范围做判断,该字符占几个字节*/
- c=(unsignedchar)str[i];
- if(c<=127)i+=0;
- elseif((c&0xE0)==0xC0)i+=1;
- if((c&0xF0)==0xE0)i+=2;
- if((c&0xF8)==0xF0)i+=3;
- return"";
- if(minIdx==std::string::npos||actualLength==std::string::npos)
- //CCLOG("result=%s",str.substr(minIdx,actualLength).c_str());
- returnstr.substr(minIdx,actualLength);
- </span>
字符编码表:
Unicode符号范围 | UTF-8编码方式 (十六进制) | (二进制) --------------------+--------------------------------------------- 0000 0000-0000 007F | 0xxxxxxx 0000 0080-0000 07FF | 110xxxxx 10xxxxxx 0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx 0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
将上面的utf8_substr函数添加到RichText.cpp中,替换类中用到substr的地方即可。 (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|