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