[Quick-x]cocos2dx下的彩色文本顯示--RichLabel

部分關鍵代碼與思路參考 http://www.cocoachina.com/bbs/read.php?tid=218977&page=1
php

感謝原做者 i7909git

代碼下載地址:https://github.com/chenquanjun/Quick-x-RichLabelgithub

----------------------數組

cocos2dx支持的文本顯示模式比較單一,不支持圖文混排與彩色文本。恰好項目要用到彩色文本,因此寫了一個簡單的類來實現ide

  • 1、介紹

支持功能測試

一、圖文混排字體

二、多彩文字混排,支持定義顏色,大小,字體等等屬性動畫

三、支持標籤內嵌ui

四、支持自動換行編碼

五、文字fadeIn動畫效果(由於是單個字符建立成精靈,可擴展成各類動畫效果)

六、支持改變文字,改變文字總體尺寸(實際上是寬度)

用於聊天系統、公告或裝備描述性文本塊(抄原做者的話啦)

還能夠用做人物對話,相似Galgame的人物對話(咳咳)

 

  • 2、原理

 一、字符串定義/規則

(1)彩色文本以[fontColor=xx]開頭,[/fontColor]結尾,若要改變字體大小,字體類型等等,在開頭框中加入對應的關鍵字(不須要加入關鍵字結尾),例如:

local str = "[fontColor=ff7f00 fontName=ArialRoundedMTBold fontSize = 30]測試[/fontColor]" --建立顏色爲ff7f00,字體名爲ArialRoundedMTBold,大小爲30的測試 label

文本支持參數 fontColor, fontSize, fontName等等

 

(2)圖片以[image=xx.png]開頭,[/image]結尾,例如圖片支持參數 image(必須), scale

local imageStr = "[image=test.png scale = 1.2][/image]" --建立文件名爲test.png的精靈,大小爲1.2

 

(3)支持圖文混排,例如

local multiStr = "[fontColor=42426f]哈哈哈哈哈哈!![/fontColor][image=wsk1.png scale=1.3][/image]"

 

二、實現原理

(1)字符串解析

1.將字符串以標籤頭[]爲關鍵字分隔字符串

    local clumpheadTab = {} -- 標籤頭
    --做用,取出全部格式爲[xxxx]的標籤頭
    for w in string.gfind(str, "%b[]") do 
        if  string.sub(w,2,2) ~= "/" then-- 去尾
            table.insert(clumpheadTab, w)
        end
    end
標籤頭分割

2.標籤解析

原理就是將標籤的定義屬性一個個分離出來而後以table來儲存

    -- 解析標籤
    local totalTab = {}
    for k,ns in pairs(clumpheadTab) do
        local tab = {}
        local tStr  
        -- 第一個等號前爲塊標籤名
        string.gsub(ns, string.sub(ns, 2, #ns-1), function (w)
            local n = string.find(w, "=")
            if n then
                local temTab = self:stringSplit_(w, " ") -- 支持標籤內嵌
                for k,pstr in pairs(temTab) do
                    local temtab1 = self:stringSplit_(pstr, "=")
                    
                    local pname = temtab1[1]

                    if k == 1 then 
                        tStr = pname 
                    end -- 標籤頭
                    
                    local js = temtab1[2]

                    local p = string.find(js, "[^%d.]")

                    if not p then 
                        js = tonumber(js) 
                    end

                    local switchState = {
                        ["fontColor"]     = function()
                            tab["fontColor"] = self:convertColor_(js)
                        end,
                    } --switch end

                    local fSwitch = switchState[pname] --switch 方法

                    --存在switch
                    if fSwitch then 
                        --目前只是顏色須要轉換
                        local result = fSwitch() --執行function
                    else --沒有枚舉
                        tab[pname] = js        
                        return
                    end
                end
            end
        end)
        if tStr then
            -- 取出文本
            local beginFind,endFind = string.find(str, "%[%/"..tStr.."%]")
            local endNumber = beginFind-1
            local gs = string.sub(str, #ns+1, endNumber)
            if string.find(gs, "%[") then
                tab["text"] = gs
            else
                string.gsub(str, gs, function (w)
                    tab["text"] = w
                end)
            end
            -- 截掉已經解析的字符
            str = string.sub(str, endFind+1, #str)
            table.insert(totalTab, tab)
        end
    end
標籤解析

 

(2)字符分隔

主要用了Unicode編碼的原理分隔字符串,此處就不展開了

簡單來講就是每一個字符的第一位定義了該字符佔據了多少字節。這個能夠用排隊來理解,若是每一個人都同樣體型的話,n我的的隊列長度是必定的,可是若是有些人長得胖有些人長得瘦,那麼隊列的長度就不肯定了,因而乎咱們定了一個規則

最瘦的佔1個空間,比較瘦的佔2個空間,如此類推,只要在範圍內的都固定相同空間,而後在頭上貼個標籤說明他是哪一個分段的。這樣的話咱們只要不斷讀取他們的頭(-,-),就能夠把他們分出來了。

    local list = {}
    local len = string.len(str)
    local i = 1 
    while i <= len do
        local c = string.byte(str, i)
        local shift = 1
        if c > 0 and c <= 127 then
            shift = 1
        elseif (c >= 192 and c <= 223) then
            shift = 2
        elseif (c >= 224 and c <= 239) then
            shift = 3
        elseif (c >= 240 and c <= 247) then
            shift = 4
        end
        local char = string.sub(str, i, i+shift-1)
        i = i + shift
        table.insert(list, char)
    end
    return list, len
字符分隔

 

(3)精靈建立

前面已經把字符串都分割成單個字符了,這裏就是簡單的建立精靈了,由於只有兩種,因此區分一下用label仍是sprite來建立便可

--建立精靈
function RichLabel:createSprite_(parseArray)
    local spriteArray = {}

    for i, dic in ipairs(parseArray) do
        local textArr = dic.textArray
        if #textArr > 0 then --建立文字
            local fontName = dic.fontName or self._fontName
            local fontSize = dic.fontSize or self._fontSize
            local fontColor = dic.fontColor or self._fontColor
            for j, word in ipairs(textArr) do
                local label = CCLabelTTF:create(word, fontName, fontSize)
                label:setColor(fontColor)
                spriteArray[#spriteArray + 1] = label
                self._containLayer:addChild(label)
            end
        elseif dic.image then
            local sprite = CCSprite:create(dic.image)
            local scale = dic.scale or 1
            sprite:setScale(scale)
            spriteArray[#spriteArray + 1] = sprite
            self._containLayer:addChild(sprite)
        else
            error("not define")
        end
    end

    return spriteArray
end
建立精靈

 

(4)位置調整

字符串解析和位置調整是richlabel實現的關鍵,主要是經過實際建立精靈而後得到精靈的大小,而後按順序"填"到指定的區域之中,遇到邊界則換行

--得到每一個精靈的位置
function RichLabel:getPointOfSprite_(widthArr, heightArr, dimensions)
    local totalWidth = dimensions.width
    local totalHight = dimensions.height

    local maxWidth = 0
    local maxHeight = 0

    local spriteNum = #widthArr

    --從左往右,從上往下拓展
    local curX = 0 --當前x座標偏移
    
    local curIndexX = 1 --當前橫軸index
    local curIndexY = 1 --當前縱軸index
    
    local pointArrX = {} --每一個精靈的x座標

    local rowIndexArr = {} --行數組,以行爲index儲存精靈組
    local indexArrY = {} --每一個精靈的行index

    --計算寬度,並自動換行
    for i, spriteWidth in ipairs(widthArr) do
        local nexX = curX + spriteWidth
        local pointX
        local rowIndex = curIndexY

        local halfWidth = spriteWidth * 0.5
        if nexX > totalWidth and totalWidth ~= 0 then --超出界限了
            pointX = halfWidth
            if curIndexX == 1 then --當前是第一個,
                curX = 0-- 重置x
            else --不是第一個,當前行已經不足容納
                rowIndex = curIndexY + 1 --換行
                curX = spriteWidth
            end
            curIndexX = 1 --x座標重置
            curIndexY = curIndexY + 1 --y座標自增
        else
            pointX = curX + halfWidth --精靈座標x
            curX = pointX + halfWidth --精靈最右側座標
            curIndexX = curIndexX + 1
        end
        pointArrX[i] = pointX --保存每一個精靈的x座標

        indexArrY[i] = rowIndex --保存每一個精靈的行

        local tmpIndexArr = rowIndexArr[rowIndex]

        if not tmpIndexArr then --沒有就建立
            tmpIndexArr = {}
            rowIndexArr[rowIndex] = tmpIndexArr
        end
        tmpIndexArr[#tmpIndexArr + 1] = i --保存相同行對應的精靈

        if curX > maxWidth then
            maxWidth = curX
        end
    end

    local curY = 0
    local rowHeightArr = {} --每一行的y座標

    --計算每一行的高度
    for i, rowInfo in ipairs(rowIndexArr) do
        local rowHeight = 0
        for j, index in ipairs(rowInfo) do --計算最高的精靈
            local height = heightArr[index]
            if height > rowHeight then
                rowHeight = height
            end
        end
        local pointY = curY + rowHeight * 0.5 --當前行全部精靈的y座標(正數,未取反)
        rowHeightArr[#rowHeightArr + 1] = - pointY --從左往右,從上到下擴展,因此是負數
        curY = curY + rowHeight --當前行的邊緣座標(正數)

        if curY > maxHeight then
            maxHeight = curY
        end
    end

    self._maxWidth = maxWidth
    self._maxHeight = maxHeight

    local pointArrY = {}

    for i = 1, spriteNum do
        local indexY = indexArrY[i] --y座標是先讀取精靈的行,而後再找出該行對應的座標
        local pointY = rowHeightArr[indexY]
        pointArrY[i] = pointY
    end

    return pointArrX, pointArrY
end
位置調整

 

  • 3、測試

測試(1):改變大小 (淺灰色的是設置的尺寸,深灰色的是文字實際的尺寸)

目前僅實現了寬度適應

 

測試(2)設置文字測試

測試(3)動畫測試

 

相關文章
相關標籤/搜索