1. 程式人生 > >cocos2dx中RichText富文字的換行問題

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