码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-06-15 23:59:09      阅读:1228      评论:0      收藏:0      [点我收藏+]

标签:cocos2dx   richtext   换行   

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


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


RichText的换行原理:


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


  1. <span style="font-size:14px;">void RichText::handleTextRenderer(const char *text, const char *fontName, float fontSize, const ccColor3B &color, GLubyte opacity)  
  2. {  
  3.     /* 不换行时的label */  
  4.     CCLabelTTF* textRenderer = CCLabelTTF::create(text, fontName, fontSize);  
  5.     /* 不换行时的label宽度 */  
  6.     float textRendererWidth = textRenderer->getContentSize().width;  
  7.     /* 用设定的大小 - label宽度 */  
  8.     _leftSpaceWidth -= textRendererWidth;  
  9.     if (_leftSpaceWidth < 0.0f)  
  10.     {  
  11.         /* 需要换行,则需要按比例截取原字符串:先计算超出的宽度所占的比例 */  
  12.         float overstepPercent = (-_leftSpaceWidth) / textRendererWidth;  
  13.         std::string curText = text;  
  14.         /* 计算字符串的长度 */  
  15.         int stringLength = curText.length();  
  16.         /* 1-超出比例 = 当前(设定宽度所占比) 来截取字符串 */  
  17.         int leftLength = stringLength * (1.0f - overstepPercent);  
  18.         /* 使用stl标准库的string函数截取字串 */  
  19.         std::string leftWords = curText.substr(0, leftLength);  
  20.         std::string cutWords = curText.substr(leftLength, curText.length()-1);  
  21.         /* 字符串不为空,则绘制第一行label */  
  22.         if (leftLength > 0)  
  23.         {  
  24.             CCLabelTTF* leftRenderer = CCLabelTTF::create(leftWords.substr(0, leftLength).c_str(), fontName, fontSize);  
  25.             leftRenderer->setColor(color);  
  26.             leftRenderer->setOpacity(opacity);  
  27.             pushToContainer(leftRenderer);  
  28.         }  
  29.           
  30.         /* 开启新的一行,并作递归处理 */  
  31.         addNewLine();  
  32.         handleTextRenderer(cutWords.c_str(), fontName, fontSize, color, opacity);  
  33.     }  
  34.     else  
  35.     {  
  36.         textRenderer->setColor(color);  
  37.         textRenderer->setOpacity(opacity);  
  38.         pushToContainer(textRenderer);  
  39.     }</span>  

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

  1. <span style="font-size:14px;">/*参数如下: 
  2.  *str:原字符串 
  3.  *start:截串的起始位置(起始位置未必准确,通过判断调整) 
  4.  *leng:截取的长度(同样长度未必准确) 
  5.  */  
  6. static std::string utf8_substr(const std::string& str, unsigned long start, unsigned long leng)  
  7.     {  
  8.         if (leng==0)  
  9.         {  
  10.             return "";  
  11.         }  
  12.         unsigned long c, i, strLen, minIdx=std::string::npos, actualLength=std::string::npos;  
  13.         //有效(不乱码)的起始位置和有效原的截取长度与参数有偏移差  
  14.         long startOffset,lenOffset;  
  15.         for (i=0, strLen=str.length(); i <= strLen; i++)  
  16.         {  
  17.             //i 按照字符所占的字节数做跳转的,utf-8中文字符时 i 的值0 3 6 9.....  
  18.             if (i <= start)  
  19.             {  
  20.                 minIdx = i; //保证最小索引在一个字符的初始字节上(中文字符有3个字节,这里指第一个字节)  
  21.                 startOffset = start - minIdx;  
  22.             }  
  23.               
  24.             if (i <= start+leng)  
  25.             {  
  26.                 lenOffset = start+leng - i;  
  27.                 actualLength = leng + abs(startOffset) - abs(lenOffset); //多余的字节放到下一段处理  
  28.             }  
  29.               
  30.             /* 于所有字符的编码表中的范围做判断,该字符占几个字节 */  
  31.             c = (unsigned char) str[i];  
  32.             if      (c<=127) i+=0;  
  33.             else if ((c & 0xE0) == 0xC0) i+=1;  
  34.             else if ((c & 0xF0) == 0xE0) i+=2;  
  35.             else if ((c & 0xF8) == 0xF0) i+=3;  
  36.             else return "";//invalid utf8  
  37.         }  
  38.         if (minIdx==std::string::npos || actualLength==std::string::npos)  
  39.         {  
  40.             return "";  
  41.         }  
  42.         //CCLOG("       result = %s",str.substr(minIdx,actualLength).c_str());  
  43.         return str.substr(minIdx,actualLength);  
  44.     }  
  45. </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的地方即可。

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

标签:cocos2dx   richtext   换行   

原文地址:http://blog.csdn.net/ys5773477/article/details/46508617

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!