图文混排

local ImgTextControl = class(ImgTextControl,function() return cc.Node:create() end)
TextHAlignment =
{
    LEFT=0,
    CENTER=1,
    RIGHT=2
}
TextVAlignment = 
{
    TOP=0,
    CENTER=1,
    BOTTOM=2,
}
local defaultHelvetica = "Marker Felt"
local defaultFontSize = 25
local defaultOpacity = 255
local defaultTextColor = cc.c3b(0xE7, 0xDB, 0xC5)--文本颜色
local defaultLineColor = cc.c3b(0xFF, 0xD2, 0x0)--下划线颜色
local defaultAnchor = cc.p(0.5, 0.5)--label默认锚点
local defaultAlignment = {HAlignment = TextHAlignment.LEFT, VAlignment = TextVAlignment.TOP}
local leftCenterAnchor = cc.p(0, 0)--锚点
local specialWord = {",", ":", ";", "、", "+"}

--text 
--Alignment = {HAlignment = label:getTextHorizontalAlignment(), VAlignment = label:getTextVerticalAlignment()}
--H_Height 换行的额外高度
function ImgTextControl:ctor(text, dimensionsSize, fontSize, fontColor, lineColor, anchor, Alignment, isAjust, H_Height, isSingleLine, isOutLine)
    -- assert(false)
    -- text = text or "nil"
    text = string.format("这是入冬以来#n,胶东半岛#I(Zhuangbei_ToukuiTest.png)#n上#C(#ffd200)%s#n。雪纷纷扬扬,#U下得很大,很大。#n大雪整整下了一夜。今天早晨,天放晴了,太阳出来了。#H换行换行换行换行换行换行行行#I(Zhuangbei_ToukuiTest.png)#n#C(#ffd200)推开门一看,嗬!#n#C(#db0101)好大的雪啊!#n清晨的阳光,显出一道道#C(#3dcc16)%s#n!", "第一场雪", "五光十色的彩虹")
    self.m_sText = text
    -- CCLOG("text = "..text)
    self.m_tDimensionsSize = dimensionsSize
    self.m_bSingleLine = isSingleLine
    if self.m_tDimensionsSize and self.m_bSingleLine then
        self.m_tDimensionsSize.width = g_uiSize.width
    end
    self.m_iFontSize = fontSize or defaultFontSize
    self.m_tDefaultTextColor = fontColor or defaultTextColor
    self.m_tDefaultLineColor = lineColor or defaultLineColor
    self.m_tAnchor = anchor or defaultAnchor
    self.m_tAlignment = Alignment or defaultAlignment
    self.m_bAjust = isAjust
    self.m_iSingleHight = g_createWithSystemFont_Shadow("M", self.m_iFontSize):getContentSize().height
    self.m_iH_Height = H_Height or 0
    self.m_iOffsetX = 0 
    self.m_bOutLine = isOutLine--是否描边

    self.m_pNode = cc.Node:create()
    self:addChild(self.m_pNode)
    self:setCascadeOpacityEnabled(true)
    self.m_pNode:setCascadeOpacityEnabled(true)
    self:initData(text)
end

function ImgTextControl:initData(text)
    self.m_pNode:removeAllChildren() 
    self.m_tRichItem = {}
    self.m_tLinwMaxY = {}
    self.m_tNewSize = {}
    self.m_tRowWidth = {}
    self.m_tPos = cc.p(self.m_iOffsetX, 0)
    self.m_iLineNum = 1
    self.m_tCurLineMaxHeight = 0
    self.m_iMaxX = 0
    self.m_iFun = nil
    self.m_pNode:setPosition(cc.p(0, 0))
    self.m_tNewLine = {}


    local totalTime = 0
    local startTime = os.clock()
    local richItemCfg = self:getCfgByText(text)
    for k,v in pairs(richItemCfg) do
       self:getItem(v)
    end
    self:ajustPosition()
    totalTime = os.clock()-startTime
end

function ImgTextControl:getItem(tableItem)
    --CCLOG(tableItem, "tableItem") 
    if tableItem.imgPath then
        self:getImg(tableItem)
    elseif tableItem.str then
        self:getLab(tableItem)
    end
end

function ImgTextControl:getImg(tableItem)
    local item=cc.Sprite:create(tableItem.imgPath)
    -- local item=cc.Sprite:create("test.png")
    self.m_pNode:addChild(item)
    item:setAnchorPoint(cc.p(0,0))
    self:setPositionByItem(item)
end

function ImgTextControl:getLab(tableItem)
    local textStr = tableItem.str
    if tableItem.isH then
        self.m_iLineNum = self.m_iLineNum + 1
        self.m_tPos.y = self.m_tPos.y - self.m_iH_Height
        self.m_tPos.x = self.m_iOffsetX
        self.m_tCurLineMaxHeight = 0
    end
    local len = string.utf8len(textStr)
    local index = 1
    local function newLine(item, str)
        item:setVisible(false)
        item.freshFlag = true
        local itemSize = item:getContentSize()
        local itemParent = item:getParent()
        local itemPosX, itemPosY = item:getPosition()
        --下划线
        local r,b,g = self.m_tDefaultLineColor["r"], self.m_tDefaultLineColor["b"], self.m_tDefaultLineColor["g"]
        local pColorLayer = cc.LayerColor:create(cc.c4b(r, g, b, 255))
        pColorLayer:setContentSize(cc.size(itemSize.width, 2))--层的高度设为2,所以看上去是下划线
        itemParent:addChild(pColorLayer)
        pColorLayer:setPosition(cc.p(itemPosX, itemPosY))
        pColorLayer.lineNum = self.m_iLineNum
        pColorLayer.underLine = true
        table.insert(self.m_tNewLine,pColorLayer)
        --超链接文本
        local itemNew = g_createWithSystemFont_Shadow(item:getString(), self.m_iFontSize, self.m_tDefaultLineColor) 
        itemParent:addChild(itemNew)
        itemNew:setAnchorPoint(cc.p(0.5, 0.5))
        itemNew:setPosition(cc.p(itemPosX+itemSize.width/2, itemPosY + itemSize.height/2))
        itemNew.lineNum = self.m_iLineNum
        table.insert(self.m_tNewLine,itemNew)
        -- --注册点击事件
        local path = "new_ui/Common_Picture_Toumingtu.png"
        local button = ccui.Button:create(path, nil, nil, g_texture_normal_format)
        itemParent:addChild(button)
        button:setPosition(cc.p(itemPosX+itemSize.width/2, itemPosY+itemSize.height/2))
        button.lineNum = self.m_iLineNum
        table.insert(self.m_tNewLine,button)
        local function clickBtn(_obj, _event)
            if _event == 2 or _event == 3 then
                _obj.itemNew:setScale(1)
            else
                _obj.itemNew:setScale(1.1)
            end
            if _event == 2 and self.m_iFun then
                self.m_iFun()
            end
        end 
        button:addTouchEventListener(clickBtn)
        button:setScale9Enabled(true)
        button:setContentSize(cc.size(itemSize.width, itemSize.height))
        button.itemNew = itemNew
    end
    local isU = tableItem.isU
    --处理特殊的中文字符
    local function handlerSpecialWord(_str, newLabFun)
        if false then
            newLabFun(_str)
            return
        end
        local isSpec = false
        for k,v in pairs(specialWord) do
            if v==_str then
                isSpec = true
                newLabFun(_str)
                break
            elseif string.find(_str, v) then--功能:类似“测试,分开”拆分成3个部分"测试",",","分开"
                isSpec = true
                local tStr = string.split(_str, v)
                local len = #tStr
                local curPos = 2
                for i=1,len do
                    if i ~= len then
                        table.insert(tStr, curPos, v)
                    end
                    curPos = curPos + 2
                end
                -- CCLOG(tStr, "tStr_2")
                for i,val in ipairs(tStr) do
                    newLabFun(val)
                end
                break
            end
        end
        if not isSpec then
            newLabFun(_str)
        end
    end

    local function newLab( str )
        local item
        if self.m_bOutLine then--描边
            item = g_createOutLineLab(str, self.m_iFontSize, tableItem.color or self.m_tDefaultTextColor)
        else--阴影
            item = g_createWithSystemFont_Shadow(str, self.m_iFontSize, tableItem.color or self.m_tDefaultTextColor)
        end
        item.str = str
        local itemSize = item:getContentSize()
        local newWidth = self.m_tPos.x + itemSize.width
        self.m_pNode:addChild(item)
        item:setAnchorPoint(leftCenterAnchor)
        if self.m_tDimensionsSize and newWidth > self.m_tDimensionsSize.width then --当前行超宽
            local leftWidth = self.m_tDimensionsSize.width - self.m_tPos.x 
            local index = math.floor(leftWidth/itemSize.width * string.utf8len(str))--计算当前行能放下字符的索引
            local newStr = string.utf8sub(str, 1, index)
            local leftStr = string.utf8sub(str, index+1, len)
            item:setString(newStr)
            local function compareWidth()--这个函数的功能是处理最后一个子放不下的时候把它到第二行去
                local newItemSize = item:getContentSize()
                local newWidth1 = self.m_tPos.x+newItemSize.width
                if newWidth1 > self.m_tDimensionsSize.width + self.m_iFontSize*0.6 and index > 2 then
                    index = index - 1
                    newStr = string.utf8sub(str, 1, index)
                    leftStr = string.utf8sub(str, index+1, len)
                    item:setString(newStr)
                    compareWidth()                    
                end
            end
            compareWidth()
            item.str = newStr
            self:setPositionByItem(item)
            if isU then
                newLine(item, newStr)
            end
            self.m_iLineNum = self.m_iLineNum + 1
            self.m_tPos.x = self.m_iOffsetX
            self.m_tCurLineMaxHeight = 0
            handlerSpecialWord(leftStr, newLab)--处理放不下的到第二行
        else
            item.str = str
            self:setPositionByItem(item)
            self.m_tPos.x = newWidth
            if isU then
                newLine(item, str)
            end
        end
        if self.m_tDimensionsSize and newWidth > self.m_tDimensionsSize.width then
            self.m_iMaxX = self.m_tDimensionsSize.width
        else
            if self.m_iMaxX < newWidth then
                self.m_iMaxX = newWidth
            end 
        end
    end
    handlerSpecialWord(textStr, newLab)
end

function ImgTextControl:addLabelTouchEventListeners(fun)
    self.m_iFun = fun
end

function ImgTextControl:getContentSize()
    return self.m_tDimensionsSize or self:getFactContentSize()
end

function ImgTextControl:getFactContentSize()--获取整个富文本矩形大小
    local maxYCnt = table.getn(self.m_tLinwMaxY)
    if maxYCnt > 0 then
        self.m_iMaxY = math.abs(self.m_tLinwMaxY[maxYCnt].y or self.m_iSingleHight)
        local lineNum = self:getLineNum()
        local factSizeW
        if lineNum > 1 and self.m_tDimensionsSize then
            factSizeW = self.m_tDimensionsSize.width
        else
            factSizeW = self.m_iMaxX
        end
        if self.m_bAjust then
            factSizeW = self.m_iMaxX
        end
        local factSize = cc.size(factSizeW, self.m_iMaxY)
        -- CCLOG(factSize, "factSize")
        return factSize
    else
        return cc.size(0, 0)
    end
end

function ImgTextControl:ajustPosition()
    --根据锚点设置位置
    local tFactContentSize = self:getFactContentSize()
    local tDimensionsSize = self.m_tDimensionsSize or self:getContentSize()
    -- CCLOG({tFactContentSize = tFactContentSize, tDimensionsSize = tDimensionsSize})
    local x = self.m_pNode:getPositionX()
    self.m_pNode:setPosition(cc.p(x - self.m_tAnchor.x*tDimensionsSize.width, tDimensionsSize.height - self.m_tAnchor.y*tDimensionsSize.height))

    --同行位置y相同
    local tLastLineLab = {}
    for k,v in pairs(self.m_tRichItem) do
        if self.m_tLinwMaxY[v.lineNum] then
            v:setPositionY((self.m_tLinwMaxY[v.lineNum].y or 0))
            local itemSize = v:getContentSize()
            if v.str then
                print(v.str,self.m_tLinwMaxY[v.lineNum].y,itemSize.height,self.m_tLinwMaxY[v.lineNum].maxHeight)
            end
            if itemSize.height < self.m_tLinwMaxY[v.lineNum].maxHeight then
                if v.freshFlag then --修复下划线的位置不正确问题
                    for key,newLine in pairs(self.m_tNewLine) do
                        if newLine.lineNum == v.lineNum then
                            if newLine.underLine then
                                newLine:setPositionY(self.m_tLinwMaxY[v.lineNum].y + (self.m_tLinwMaxY[v.lineNum].maxHeight - itemSize.height)/2 )
                            else
                                newLine:setPositionY(self.m_tLinwMaxY[v.lineNum].y + (self.m_tLinwMaxY[v.lineNum].maxHeight - itemSize.height)/2 +itemSize.height/2)
                            end
                        end
                    end
                else
                    v:setPositionY(self.m_tLinwMaxY[v.lineNum].y + (self.m_tLinwMaxY[v.lineNum].maxHeight - itemSize.height)/2 )
                end
            end
        end
        if self.m_iLineNum == v.lineNum then
            table.insert(tLastLineLab, v)
        end
    end

    --所有行居中
    for k,v in pairs(self.m_tRichItem) do
        if self.m_tDimensionsSize then
            local maxWidth = self.m_tRowWidth[v.lineNum]
            local x = v:getPositionX()
            local AlignmentOffsetX = self.m_iOffsetX
            if self.m_tAlignment.HAlignment == TextHAlignment.LEFT then
                AlignmentOffsetX = self.m_iOffsetX
            elseif self.m_tAlignment.HAlignment == TextHAlignment.CENTER then
                AlignmentOffsetX = (self.m_tDimensionsSize.width - maxWidth)/2
            elseif self.m_tAlignment.HAlignment == TextHAlignment.RIGHT then
                AlignmentOffsetX = self.m_tDimensionsSize.width - maxWidth
            end

            v:setPositionX(x+AlignmentOffsetX)
            -- CCLOG("水平位置 ".."v.lineNum = "..v.lineNum.." maxWidth = "..maxWidth.." OffsetX = "..AlignmentOffsetX)
        else
            -- CCLOG("没有水平位置!")
        end
    end


    --根据竖直对齐方式设置位置
    local newY = 0
    local sString = ""
    -- CCLOG(self.m_tAlignment, "self.m_tAlignment")
    if self.m_tAlignment.VAlignment == TextVAlignment.TOP then
        newY = tDimensionsSize.height - self.m_tAnchor.y*tDimensionsSize.height
        sString = "TOP newY = "..newY
    elseif self.m_tAlignment.VAlignment == TextVAlignment.CENTER then
        newY = tFactContentSize.height/2
        sString = "CENTER newY = "..newY
    elseif self.m_tAlignment.VAlignment == TextVAlignment.BOTTOM then
        newY = tFactContentSize.height - self.m_tAnchor.y*tDimensionsSize.height
        sString = "BOTTOM newY = "..newY
    end
    if self.m_tDimensionsSize then 
        --设置位置
        self.m_pNode:setPositionY(newY)
    end
end

function ImgTextControl:setPositionByItem(item)
    local itemSize = item:getContentSize()
    if self.m_tCurLineMaxHeight < itemSize.height then
        local itemH = itemSize.height
        self.m_tPos.y = self.m_tPos.y - itemH + self.m_tCurLineMaxHeight
        self.m_tCurLineMaxHeight = itemH
        self.m_tLinwMaxY[self.m_iLineNum] = {}
        self.m_tLinwMaxY[self.m_iLineNum].y = self.m_tPos.y
        self.m_tLinwMaxY[self.m_iLineNum].maxHeight = itemH
    end
    item.lineNum = self.m_iLineNum
    table.insert(self.m_tRichItem, item)
    item:setPosition(self.m_tPos)
    self.m_tPos.x = self.m_tPos.x + itemSize.width
    self.m_tRowWidth[item.lineNum] =  self.m_tPos.x
end

function ImgTextControl:getCfgByText(text)
    text = text or ""
    text = string.gsub(text, "#C", "#n#C")
    --#n 分隔符
    local tSubStr1 = string.split(text, "#n")
    --#H 换行符
    local tSubStr2 = {}
    for k,v in pairs(tSubStr1) do
        local pos = string.find(v, "#H")
        local tTemp = string.split(v, "#H")
        for key,val in pairs(tTemp) do
            local t = {str = val,}
            if pos == 1 then
                t.isH = true
            else
                if key ~= 1 then
                    t.isH = true
                end
            end
            table.insert(tSubStr2, t)
        end
    end--这一步去掉了#H
    -- CCLOG(tSubStr2, "tSubStr2 #H")
    --#U 下划线
    local tSubStr4 = {}
    for k,v in ipairs(tSubStr2) do
        local pos = string.find(v.str, "#U")
        local tTemp = string.split(v.str, "#U")
        for key,val in pairs(tTemp) do
            if string.utf8sub(val, -1, -1) == "#" then --如果切分出来的块最后一个字符是"#",则舍弃(如:cishi#,#)
                val = string.sub(val, 1, -2)
            end
            local t = {str = val, isH = (v.isH and key==1) }
            if pos == 1 then
                t.isU = true
            else
                if key ~= 1 then
                    t.isU = true
                end
            end
            table.insert(tSubStr4, t)
        end
    end--这一步去掉了#U
    -- CCLOG(tSubStr4, "tSubStr4 #U")
    --#(
    local tSubStr3 = {}
    for k,v in pairs(tSubStr4) do
        local pos = string.find(v.str, "#")
        if pos then
            local cPos = string.find(v.str, "C%(")
            if cPos then
                local tTemp = string.split(v.str, "C(")
                for key,val in pairs(tTemp) do
                    local t = {str = val, isU = v.isU}
                    if key==1 then
                        t.isH = v.isH
                    end
                    table.insert(tSubStr3, t)
                end
            else
                local tTemp = string.split(v.str, "(")
                for key,val in pairs(tTemp) do
                    local t = {str = val, isU = v.isU}
                    if key==1 then
                        t.isH = v.isH
                    end
                    table.insert(tSubStr3, t)
                end
            end
        else
            table.insert(tSubStr3, v)
        end
    end
    -- CCLOG(tSubStr3, "tSubStr3 #(")
    local richItemCfg = {}
    for k,v in pairs(tSubStr3) do
        richItemCfg[k] = v
        if string.find(v.str, ".png") then
            v.imgPath = string.utf8sub(v.str, 1, -2)--去掉")"
        elseif string.sub(v.str, -2, -2) == "#" then--去掉#i
            v.str = string.sub(v.str, 1, -3)
        elseif string.sub(v.str, 1, 1) == "#" then--取出颜色,跟颜色后面的字符串,顺便再清理一次单独的#
            v.color = self:getColor(string.sub(v.str, 2, 7))
            v.str = string.sub(v.str, 9, -1)
        end
    end
    --单独的#变成""
    local itemLen = table.getn(richItemCfg)
    for i=itemLen,1,-1 do
        if richItemCfg[i] then
            if richItemCfg[i].str == "" 
               or richItemCfg[i].str == nil then
                -- table.remove(richItemCfg, i)
                richItemCfg[i].str = ""
            end
        end
    end
    -- CCLOG(richItemCfg, "richItemCfg")
    return richItemCfg
end

function ImgTextControl:getColor(c)
    local a = c or "369119"
    local color = {255,255,255}
    local colorCount = 1 
    local as = string.utf8sub(tostring(a),1)
    while as and as~="" do 
        local c16 = string.utf8sub(as,1,2)
        as = string.utf8sub(tostring(as),3)
        color[colorCount] = tonumber(string.format("%d","0x"..c16))--将16进制转换为10进制
        colorCount = colorCount + 1
    end 
    return cc.c3b(color[1],color[2],color[3])
end 

function ImgTextControl:setString(text, H_Height)
    self.m_iH_Height = H_Height or 0
    self:initData(text)
end

function ImgTextControl:getLineNum()
    return self.m_iLineNum
end

function ImgTextControl:getString()
    return self.m_sText or ""
end

function g_createOutLineLab(str,fontSize,textColor_c4,outLine_c4)
    local ttfConfig = {}
    ttfConfig.fontFilePath = g_ttfFile
    ttfConfig.fontSize = fontSize
    ttfConfig.glyphs   = cc.GLYPHCOLLECTION_DYNAMIC
    ttfConfig.customGlyphs = nil
    ttfConfig.distanceFieldEnabled = true --设置是否紧凑
    ttfConfig.outlineSize = 1 --描边大小

    local s = cc.Director:getInstance():getWinSize()
    local outLineLabel = cc.Label:createWithTTF(ttfConfig, str, cc.TEXT_ALIGNMENT_CENTER)
    outLineLabel:setColor(textColor_c4)
    outLineLabel:setAdditionalKerning(-fontSize*0.15)--设置字间距
    outLineLabel.isOutline = true --描边
    return outLineLabel
end

g_ttfConfig = {}
g_ttfConfig.fontFilePath = g_ttfFile
g_ttfConfig.fontSize = 22
g_ttfConfig.glyphs   = cc.GLYPHCOLLECTION_DYNAMIC --  DYNAMIC ,NEHE ,ASCII,CUSTOM
--ttfConfig.customGlyphs = str -- 自定义 不知道 有什么用
g_ttfConfig.distanceFieldEnabled = true --是否开启描边字效果
g_ttfConfig.outlineSize = 1 -- 描边的大小  小于0 自动关闭

-- 系统 阴影效果
function g_createWithSystemFont_Shadow(str,fontSize,textColor_c4,outLine_c4) 
    --local label1 = cc.Label:create(str)
    local label1 = cc.Label:createWithTTF(g_ttfConfig,str)
    g_setLabelParameter(label1,str,fontSize,textColor_c4,textShadow_c4) 
    return label1
end 

-- 设置label 属性
function g_setLabelParameter(label1,str,fontSize,textColor_c4,outLine_c4)

    local ttfConfig = clone(g_ttfConfig)
    ttfConfig.fontSize = fontSize

    local lableFontSize = g_getFontSize(label1)
    if lableFontSize~=ttfConfig.fontSize  then 
        label1:setTTFConfig(ttfConfig)
    end 

    label1:setDimensions(0,0) 
    label1:setString(str)

    if textColor_c4 then 
        textColor_c4.a = textColor_c4.a or 255
    end 

    label1:setTextColor( textColor_c4 or cc4WHITE)
    label1:disableEffect()

    if outLine_c4 then 
        label1:enableOutline( outLine_c4  )
    end 
end 

return ImgTextControl

这个实现有一个小问题,就是有标点符号的时候,右边会参差不齐。如下图这样:
这里写图片描述
如果每行都是文字没有一个标点,肯定是没有对齐的问题的。然后就想出一个办法,统计每行的标点个数和超出行宽时最后那里剩下的宽度,然后除以标点数,就得到应该发生的位移,这样就能保证后面的每行都能跟第一行后边完全对齐。最终效果如下图,实现了富文本跟图片的图文混排。
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值