cocos2dx-lua 简单的字体变色拼接实现

  这里主要做的是游戏公告里面用到的,因此我加入了简单的html <font>标签解析,是为了给运营小白预览,但其中的size 属性没有,因为后来没有这个需求了,所以也就懒得改了。

  实现思路很简单:设置好行宽和行高,然后一个一个字往上面添加,直到达到行宽上限或者换行符,就换行,再循环。

  

--简易html label
--[[
    暂只对以下标签进行实现
    <font> 标签进行实现,可添加 size 和 color属性
    <br> 换行
--]]

--[=[
   demo:
    html = "<font size=\"50\" color=\"#ff0000\" > ab,casdjfladfasdgasdasdgasdfasdfqwetqwetrtwqrtqwerqwerqwerqwetqwetqwerqwerqwer44444444444222222222asdugowe<br>iurlsdjlkasdhga </font><font size=\"28\" color=\"#002\" > ab,21<br>iurlsdjlkasdhga </font><font size=\"22\" color=\"#2231\" > ab,12<br>12 </font><font size=\"10\" color=\"#2202\" > ab,.21<br>1 </font>"
    local lable = require ("common.HtmlLabel").new(600,html)
    lable:setPosition(400,400)
    self._lay:addChild(lable)
--]=]

local HtmlLabel = class("HtmlLabel",function()
	return Layout:create()
end)

function HtmlLabel:ctor(width , html)
    self._width = width
    self._height = 0
    self._defaultFontSize = 18
    self._defaultFontColor = 0x000000
    self:initWithString(html)
end

local headTag = "<font .->"
local lastTag = "</font>"
function HtmlLabel:initWithString(html)
    self._html = string.lower(html)
    self:removeAllChildrenWithCleanup(true)

    local labelList = {}
    html = string.gsub(html , "<br>"  , "\n")
    while string.len(html) > 0  do
        local bPos,ePos = string.find(html,lastTag)
        local node = {}
        local headTagEndPos = 1
        if not find then
            local hbPos,hePos = string.find(html,headTag)
            if hbPos then
--                local head = string.sub(html , hbPos , (hePos-hbPos+1))
                local head = string.sub(html , hbPos+5 , (hePos-1))
                head = string.gsub(head , "#" , "0x")
                head = string.gsub(head , "(%d\")" , "%1,")
                local strFunc = " return {" .. head .. "}"
                node = assert(loadstring(strFunc))()
                if not node.color then
                    node.color = self._defaultFontColor
                else
                    node.color = tonumber(node.color)
                end
                if not node.size then
                    node.size = self._defaultFontSize
                else
                    node.size = tonumber(node.size)
                end
                headTagEndPos = hePos + 1
               -- html = string.sub(html, hePos+1 , string.len(html))
            else
                node.color = self._defaultFontColor
                node.size = self._defaultFontSize
            end

            node.str = string.sub(html,headTagEndPos,bPos-1)
            html = string.sub(html , ePos+1 , string.len(html)) --去除已处理段
        else
            node.str = html
            node.color = self._defaultFontColor
            node.size = self._defaultFontSize
            html = ""
        end
        table.insert(labelList , node)
    end
    
    if #labelList == 0 then
        return 
    end

    local node1 = labelList[1]
    self:initRichLabel(node1.str,self._width ,node1.size*(1+0.2) , node1.size , ccc3(math.floor(node1.color/0x10000), math.floor(node1.color/0x100)%0x100 , node1.color % 0x100 ))
    
    for i=2,#labelList do
        node1 = labelList[i]
   --     print ("%02x%02x%02x",math.floor(node1.color/0x10000), math.floor(node1.color/0x100)%0x100 , node1.color % 0x100 )
        self:addString(node1.str, ccc3(math.floor(node1.color/0x10000), math.floor(node1.color/0x100)%0x100 , node1.color % 0x100 ))
    end
end


function HtmlLabel:initRichLabel(content ,lineWidth , lineHeight , fntSize , color)
	self.lineWidth = lineWidth
    self.lineHeight = lineHeight
    self._fntSize = fntSize
    self._defaultColor = color
	self.widthIndex = 0
	self.rowIndex = 1
	self.nodeList = {}
    self.anchorPoint = ccp(0.5,0.5)
    self:addString(content)
end

--重新设置一个string
function HtmlLabel:setString(content , color)
    self:removeAllChildrenWithCleanup(true)
	self.widthIndex = 0
	self.rowIndex = 1
    self.nodeList = {}
    self._defaultColor = color or self._defaultColor
    self:addString(content)
end

--增加一个string 
function HtmlLabel:addString(labelStr , color)
    color = color or self._defaultColor

	if self.widthIndex >= self.lineWidth then
		self.widthIndex = 0
		self.rowIndex = self.rowIndex + 1
	end
	
	while labelStr ~= nil and labelStr ~= "" do
		local begIndex,endIndex = self:getMaxSubStr(labelStr,self.lineWidth - self.widthIndex , self._fntSize)
		if begIndex == nil then --换行
			self.widthIndex = 0
			self.rowIndex = self.rowIndex + 1
			begIndex,endIndex = self:getMaxSubStr(labelStr,self.lineWidth - self.widthIndex, self._fntSize)
		end
		local subStr = string.sub(labelStr,begIndex,endIndex)
		labelStr = string.sub(labelStr,endIndex+1,string.len(labelStr))
	    local label = Label:create()
        label:setFontSize(self._fntSize)
        local text = string.gsub(subStr, "\n", "")--去除换行符
        label:setText(text)
        label:setColor(color)

		label:setPositionX(self.widthIndex)
		self:addChild(label)
		label:setAnchorPoint(ccp(0,0))
		label.rowIndex = self.rowIndex
        label.srcX = self.widthIndex
		table.insert(self.nodeList,label)
		self.widthIndex = self.widthIndex + label:getContentSize().width
        if string.find(subStr , '\n') then --出现强制换行
			self.widthIndex = 0
			self.rowIndex = self.rowIndex + 1
        end
	end

    self:updateInset()
end

function HtmlLabel:setContentSize( w , h)
    local sz = w
    if h then
        sz = CCSize(w ,h )
    end
    self.contentSize = sz
end

function HtmlLabel:getContentSize()
    return self.contentSize
end

--更新容器所有Node的位置
function HtmlLabel:updateInset()
	local row = self.rowIndex
	if self.widthIndex == 0 then --如果最后一行还没内容
		row = row - 1
	end
    local contentSize = CCSize(self.lineWidth,row*self.lineHeight)
    local anchorY = contentSize.height * self.anchorPoint.y
    local anchorX = contentSize.width * self.anchorPoint.x
	for k,v in pairs(self.nodeList) do
		v:setPositionY((row-v.rowIndex)*self.lineHeight - anchorY)
        v:setPositionX(v.srcX - anchorX)
	end
	
	self:setContentSize(contentSize)
end

--设置锚点
function HtmlLabel:setAnchorPoint( x, y )
    local pt = nil
    if not y then
        pt = x
    else
        pt = ccp(x,y)
    end
    if pt.x == self.anchorPoint.x and pt.y == self.anchorPoint.y then
        return
    end
    self.anchorPoint = pt
    self:updateInset()
end

function HtmlLabel:setPosition( x , y )
    local pt = nil
    if not y then
        pt = x
    else
        pt = ccp(x,y)
    end
    CCNode.setPosition(self,pt)
end

--获取宽度范围内,最长子串
function HtmlLabel:getMaxSubStr(_string,width,fntSize)
	local result = ""
	local index = 1
	local is_end = true
	local index_max = string.len(_string)
	local label = Label:create()
    label:setFontSize(fntSize)

	while is_end  do	
		local firstCase = string.byte(_string,index) 
		if firstCase == nil then
			break
		end
		local caseLen = self:sizeof(firstCase)	--字符宽度
		local strCase =  string.sub(_string,index,index + caseLen-1) 
	    if strCase  == "\n" then
			result = result .. strCase
			index = index + caseLen		--保留回车返回
            break
        end
		label:setText(result .. strCase)
		local t = label:getContentSize().width*label:getScale()
		if t < width then
			result = result .. strCase
			index = index + caseLen		
		else
			is_end = false
		end
        if index>index_max then
            is_end=false
        end 
	end
	if result == "" then
		return nil
	end
	return 1,index-1
end

--获取某字符所占字节数
function HtmlLabel:sizeof(firstCase)
	if (firstCase >= 0 and firstCase  <= 0x7f) then
       return 1	
	elseif firstCase >= 0x80 and firstCase < 0xe0 then
		return 2
    elseif firstCase >= 0xe0 then
        return 3
    end
end 


function HtmlLabel:getSize()
    return CCSize(self._width , self._height)
end

return HtmlLabel

  

posted @ 2016-07-13 10:10  JohnKing_  阅读(2393)  评论(0编辑  收藏  举报