cocos2dx中RichText富文字的換行問題
wod開飛行太難誰特麼的有空刷聲望啊!還不如寫部落格!
關於富文字什麼的,之前在南京那家公司做一個國外外包iOS應用專案的時候曾經做過一個,當時的感覺是——很難。因為需要處理wordwrap,而又沒找到適合ios系統控制元件的文字寬度計算演算法,當時的處理是直接使用Label控制元件一個個去匹配適應,然後超過4行的文字,計算時間就想當長了,所以當時找了一堆都是使用html+js做富文字編輯器的。當然這算題外話,因為cocos2dx的RichText沒有換行演算法選項,也就沒有這個問題,但那逗逼的換行演算法也是坑了我…(cocos2dx 3.3)
所謂富文字,大體就是圖片等其他東西和文字混排,很多情況下圖片等看作文字單元排布。以一般思路來說,也就是做個展示容器,容器接收文字和圖片等的片段,然後容器內封裝了對排布的處理方法。而cocos2dx的RichText控制元件也就是這麼做的。
cocos2dx的富文字換行演算法…相當的…有想法?…這是相當令人無語的…寫法…上程式碼:
UIRichText.cpp:
size_t stringLength = StringUtils::getCharacterCountInUTF8String(text);
int leftLength = stringLength * (1.0f - overstepPercent);
std::string leftWords = Helper::getSubStringOfUTF8String(curText,0,leftLength);
std ::string cutWords = Helper::getSubStringOfUTF8String(curText, leftLength, stringLength - leftLength);
簡單來說,就是…如果超長了,用unicode字元數乘以超長的…長度比,然後字串直接擷取對應的字元個數來換行…那麼,面對例如測試文字測試文字測試文字123443211234
或是123443211234測試文字測試文字測試文字
這種要麼頭重腳輕要麼臀部過大的字串,放進一個element中塞給UIRichText之後,見到的不是吞文字就是斷行了…
還好他們沒去做word wrap處理…還好產品沒給我說需要加word wrap換行…
於是我把handleTextRenderer
這塊兒稍微改了下,在原來個數計算的基礎上加了兩塊操作——超了切,短了補,現在執行基本正常——暫時沒發現不正常的情況。
主要程式碼:
Label* leftRenderer = nullptr;
if (leftWords.length() > 0) {
if (fileExist)
{
leftRenderer = Label::createWithTTF(leftWords, fontName, fontSize);
}
else
{
leftRenderer = Label::createWithSystemFont(leftWords, fontName, fontSize);
}
}
if (!leftRenderer) {
return;
}
// 處理需截文字字寬度不均,前半部分超出的情況 例如 "測試文字測試文字12341234",取寬度10/16 前半部分寬度10則超出很多
while (true) {
if (leftWords.length() > 0)
{
leftRenderer->setString(leftWords);
float leftRendererWidth = leftRenderer->getContentSize().width;
tmpLeftSpaceWidth = _leftSpaceWidth;
tmpLeftSpaceWidth -= leftRendererWidth;
if (tmpLeftSpaceWidth < 0.0f) {
int leftWordsLen = (int)leftWords.length();
if (leftWordsLen <= 0) {
break;
}
else {
//cut char one by one to get the fit length
while (true) {
leftLength -= 1;
leftWords = Helper::getSubStringOfUTF8String(curText, 0, leftLength);
cutWords = Helper::getSubStringOfUTF8String(curText, leftLength, stringLength - leftLength);
if (leftWords.length() == 0) {
break;
}
if (leftWords.length() < leftWordsLen) {
break;
}
}
}
}
else {
//if _leftSpaceWidth > 0 break
break;
}
}
else {
//if leftWords is empty, break
break;
}
}
// 處理需截文字字寬度不均,後半部分超出的情況 例如 "12341234測試文字測試文字",取寬度10/16 前半部分寬度10則缺少很多
std::string lastLeftWords = leftWords;
std::string lastCutWords = cutWords;
float lastTmpLeftSpaceWidth = tmpLeftSpaceWidth;
while (true) {
if (cutWords.length() > 0)
{
int leftWordsLen = (int)leftWords.length();
while (true) {
leftLength += 1;
leftWords = Helper::getSubStringOfUTF8String(curText, 0, leftLength);
cutWords = Helper::getSubStringOfUTF8String(curText, leftLength, stringLength - leftLength);
if (cutWords.length() == 0) {
break;
}
if (leftWords.length() > leftWordsLen) {
break;
}
}
leftRenderer->setString(leftWords);
float leftRendererWidth = leftRenderer->getContentSize().width;
tmpLeftSpaceWidth = _leftSpaceWidth;
tmpLeftSpaceWidth -= leftRendererWidth;
if (tmpLeftSpaceWidth < 0.0f) {
leftWords = lastLeftWords;
cutWords = lastCutWords;
tmpLeftSpaceWidth = lastTmpLeftSpaceWidth;
leftRenderer->setString(leftWords);
break;
}
else {
lastLeftWords = leftWords;
lastCutWords = cutWords;
lastTmpLeftSpaceWidth = tmpLeftSpaceWidth;
}
}
else {
//if cutWords is empty, break
leftWords = lastLeftWords;
cutWords = lastCutWords;
tmpLeftSpaceWidth = lastTmpLeftSpaceWidth;
leftRenderer->setString(leftWords);
break;
}
}
_leftSpaceWidth = tmpLeftSpaceWidth;
leftRenderer->setColor(color);
leftRenderer->setOpacity(opacity);
pushToContainer(leftRenderer);
_leftSpaceWidth = tmpLeftSpaceWidth;
addNewLine();
handleTextRenderer(cutWords.c_str(), fontName, fontSize, color, opacity);
工程原始碼(使用cocos2dx3.3):
github