加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

cocos2d-x改底层之RichText富文本换行

发布时间:2020-12-14 21:31:42 所属栏目:百科 来源:网络整理
导读:关于字符编码的知识,请参考前辈的博客:字符串和编码格式 这里使用的是cocos2dx的2.2.3版本,底层的RictText换行机制不能满足中文换行,需要改动。由于在3.x的版本已经优化了,而且以后的项目也会转到3.x的版本,所以这里只是做一个记录,对底层换行机制的

关于字符编码的知识,请参考前辈的博客:字符串和编码格式


这里使用的是cocos2dx的2.2.3版本,底层的RictText换行机制不能满足中文换行,需要改动。由于在3.x的版本已经优化了,而且以后的项目也会转到3.x的版本,所以这里只是做一个记录,对底层换行机制的思想做一个分析,仅供学习用。


RichText的换行原理:


以文本换行为例(图片同样的道理),先用一个不带换行的label,算出该label的总长度L,然后和程序设定的宽w比较,w<L则一行足以,否则按w在L中比例来截取原字符串,作为第一行,剩余部分递归处理。看代码:


[cpp] view plain copy
  1. <spanstyle="font-size:14px;">voidRichText::handleTextRenderer(constchar*text,char*fontName,floatfontSize,153); font-weight:bold; background-color:inherit">constccColor3B&color,GLubyteopacity)
  2. {
  3. /*不换行时的label*/
  4. CCLabelTTF*textRenderer=CCLabelTTF::create(text,fontName,fontSize);
  5. /*不换行时的label宽度*/
  6. floattextRendererWidth=textRenderer->getContentSize().width;
  7. /*用设定的大小-label宽度*/
  8. _leftSpaceWidth-=textRendererWidth;
  9. if(_leftSpaceWidth<0.0f)
  10. /*需要换行,则需要按比例截取原字符串:先计算超出的宽度所占的比例*/
  11. floatoverstepPercent=(-_leftSpaceWidth)/textRendererWidth;
  12. std::stringcurText=text;
  13. /*计算字符串的长度*/
  14. intstringLength=curText.length();
  15. /*1-超出比例=当前(设定宽度所占比)来截取字符串*/
  16. intleftLength=stringLength*(1.0f-overstepPercent);
  17. /*使用stl标准库的string函数截取字串*/
  18. std::stringleftWords=curText.substr(0,leftLength);
  19. std::stringcutWords=curText.substr(leftLength,curText.length()-1);
  20. /*字符串不为空,则绘制第一行label*/
  21. if(leftLength>0)
  22. {
  23. 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);
  24. leftRenderer->setOpacity(opacity);
  25. pushToContainer(leftRenderer);
  26. }
  27. /*开启新的一行,并作递归处理*/
  28. addNewLine();
  29. handleTextRenderer(cutWords.c_str(),fontSize,color,opacity);
  30. }
  31. else
  32. textRenderer->setColor(color);
  33. textRenderer->setOpacity(opacity);
  34. pushToContainer(textRenderer);
  35. }</span>

这里的重点是截取字串的方式,自带的substr不能很好的处理多字节字符的截取,中文会出现乱码,所以用自己写的函数实现,这个函数在网上能找到,但仍然有问题,我做了一些修改,将原来的substr改为自定义的“utf8_substr”函数:

copy
    <spanstyle="font-size:14px;">/*参数如下:
  1. *str:原字符串
  2. *start:截串的起始位置(起始位置未必准确,通过判断调整)
  3. *leng:截取的长度(同样长度未必准确)
  4. */
  5. staticstd::stringutf8_substr(conststd::string&str,unsignedlongstart,87); font-weight:bold; background-color:inherit">longleng)
  6. if(leng==0)
  7. return"";
  8. unsignedlongc,i,strLen,minIdx=std::string::npos,actualLength=std::string::npos;
  9. //有效(不乱码)的起始位置和有效原的截取长度与参数有偏移差
  10. longstartOffset,lenOffset;
  11. for(i=0,strLen=str.length();i<=strLen;i++)
  12. //i按照字符所占的字节数做跳转的,utf-8中文字符时i的值0369.....
  13. if(i<=start)
  14. minIdx=i;//保证最小索引在一个字符的初始字节上(中文字符有3个字节,这里指第一个字节)
  15. startOffset=start-minIdx;
  16. if(i<=start+leng)
  17. lenOffset=start+leng-i;
  18. actualLength=leng+abs(startOffset)-abs(lenOffset);//多余的字节放到下一段处理
  19. /*于所有字符的编码表中的范围做判断,该字符占几个字节*/
  20. c=(unsignedchar)str[i];
  21. if(c<=127)i+=0;
  22. elseif((c&0xE0)==0xC0)i+=1;
  23. if((c&0xF0)==0xE0)i+=2;
  24. if((c&0xF8)==0xF0)i+=3;
  25. return"";//invalidutf8
  26. if(minIdx==std::string::npos||actualLength==std::string::npos)
  27. //CCLOG("result=%s",str.substr(minIdx,actualLength).c_str());
  28. returnstr.substr(minIdx,actualLength);
  29. </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的地方即可。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读