部分关键代码与思路参考 http://www.cocoachina.com/bbs/read.php?tid=218977&page=1

感谢原作者 i7909

代码下载地址:https://github.com/chenquanjun/Quick-x-RichLabel

----------------------

cocos2dx支持的文本显示模式比较单一,不支持图文混排与彩色文本。刚好项目要用到彩色文本,所以写了一个简单的类来实现

  • 一、介绍

支持功能

1、图文混排

2、多彩文字混排,支持定义颜色,大小,字体等等属性

3、支持标签内嵌

4、支持自动换行

5、文字fadeIn动画效果(因为是单个字符创建成精灵,可扩展成各种动画效果)

6、支持改变文字,改变文字整体尺寸(其实是宽度)

用于聊天系统、公告或装备描述性文本块(抄原作者的话啦)

还可以用作人物对话,类似Galgame的人物对话(咳咳)

  • 二、原理

1、字符串定义/规则

(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]"

2、实现原理

(1)字符串解析

1.将字符串以标签头[]为关键字分隔字符串

    local clumpheadTab = {} -- 标签头
--作用,取出所有格式为[xxxx]的标签头
for w in string.gfind(str, "%b[]") do
if string.sub(w,,) ~= "/" 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, , #ns-), 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[] if k == then
tStr = pname
end -- 标签头 local js = temtab1[] 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-
local gs = string.sub(str, #ns+, 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+, #str)
table.insert(totalTab, tab)
end
end

标签解析

(2)字符分隔

主要用了Unicode编码的原理分隔字符串,此处就不展开了

简单来说就是每个字符的第一位定义了该字符占据了多少字节。这个可以用排队来理解,如果每个人都一样体型的话,n个人的队列长度是一定的,但是如果有些人长得胖有些人长得瘦,那么队列的长度就不确定了,于是乎我们定了一个规则

最瘦的占1个空间,比较瘦的占2个空间,如此类推,只要在范围内的都固定相同空间,然后在头上贴个标签说明他是哪个分段的。这样的话我们只要不断读取他们的头(-,-),就可以把他们分出来了。

    local list = {}
local len = string.len(str)
local i =
while i <= len do
local c = string.byte(str, i)
local shift =
if c > and c <= then
shift =
elseif (c >= and c <= ) then
shift =
elseif (c >= and c <= ) then
shift =
elseif (c >= and c <= ) then
shift =
end
local char = string.sub(str, i, i+shift-)
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 > 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 + ] = label
self._containLayer:addChild(label)
end
elseif dic.image then
local sprite = CCSprite:create(dic.image)
local scale = dic.scale or
sprite:setScale(scale)
spriteArray[#spriteArray + ] = 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 =
local maxHeight = local spriteNum = #widthArr --从左往右,从上往下拓展
local curX = --当前x坐标偏移 local curIndexX = --当前横轴index
local curIndexY = --当前纵轴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 ~= then --超出界限了
pointX = halfWidth
if curIndexX == then --当前是第一个,
curX = -- 重置x
else --不是第一个,当前行已经不足容纳
rowIndex = curIndexY + --换行
curX = spriteWidth
end
curIndexX = --x坐标重置
curIndexY = curIndexY + --y坐标自增
else
pointX = curX + halfWidth --精灵坐标x
curX = pointX + halfWidth --精灵最右侧坐标
curIndexX = curIndexX +
end
pointArrX[i] = pointX --保存每个精灵的x坐标 indexArrY[i] = rowIndex --保存每个精灵的行 local tmpIndexArr = rowIndexArr[rowIndex] if not tmpIndexArr then --没有就创建
tmpIndexArr = {}
rowIndexArr[rowIndex] = tmpIndexArr
end
tmpIndexArr[#tmpIndexArr + ] = i --保存相同行对应的精灵 if curX > maxWidth then
maxWidth = curX
end
end local curY =
local rowHeightArr = {} --每一行的y坐标 --计算每一行的高度
for i, rowInfo in ipairs(rowIndexArr) do
local rowHeight =
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 + ] = - pointY --从左往右,从上到下扩展,所以是负数
curY = curY + rowHeight --当前行的边缘坐标(正数) if curY > maxHeight then
maxHeight = curY
end
end self._maxWidth = maxWidth
self._maxHeight = maxHeight local pointArrY = {} for i = , spriteNum do
local indexY = indexArrY[i] --y坐标是先读取精灵的行,然后再找出该行对应的坐标
local pointY = rowHeightArr[indexY]
pointArrY[i] = pointY
end return pointArrX, pointArrY
end

位置调整

  • 三、测试

测试(1):改变大小 (浅灰色的是设置的尺寸,深灰色的是文字实际的尺寸)

目前仅实现了宽度适应

测试(2)设置文字测试

测试(3)动画测试

[Quick-x]cocos2dx下的彩色文本显示--RichLabel的更多相关文章

  1. CSS 单行溢出文本显示省略号...的方法(兼容IE FF)(转)

    http://www.52css.com/article.asp?id=602 ===================================================     html ...

  2. Cocos2d-x下Lua调用自定义C++类和函数的最佳实践[转]

    Cocos2d-x下Lua调用C++这事之所以看起来这么复杂.网上所有的文档都没讲清楚,是因为存在5个层面的知识点: 1.在纯C环境下,把C函数注册进Lua环境,理解Lua和C之间可以互相调用的本质 ...

  3. 【转】Cocos2d-x下Lua调用自定义C++类和函数的最佳实践

    转自:http://segmentfault.com/blog/hongliang/1190000000631630 关于cocos2d-x下Lua调用C++的文档看了不少,但没有一篇真正把这事给讲明 ...

  4. Android开发之多线程下载、断点续传、进度条和文本显示

    代码实现了在Android环境下的多线程下载.断点续传.进度条显示和文本显示百分数: import java.io.BufferedReader; import java.io.File; impor ...

  5. cocos2d-x 3.0 final 中文显示

    cocos2d-x 3.0的中文显示非常easy,首先,你须要一个xml文件保存中文,还须要一个能显示中文的TTF文件 <?xml version="1.0" encodin ...

  6. 10分钟 教你学会Linux/Unix下的vi文本编辑器

    10分钟 教你学会Linux/Unix下的vi文本编辑器 vi编辑器是Unix/Linux系统管理员必须学会使用的编辑器.看了不少关于vi的资料,终于得到这个总结.不敢独享,和你们共享. 首先,记住v ...

  7. css 溢出文本显示省略号

    这个标题其实已经是一个老生常谈的问题了.很多时候,比如网站最基本的文章列表,标题会很长,而显示列表的区域宽度却没有这么宽,这时候最正常的做法就是 让超出宽度的部分文字用省略号(…)来表示.通常做法是网 ...

  8. EmWin 文本显示函数

    函数模型----------------------------------- 1:void GUI_DispChar(U16 c):  在当前窗口的当前文本位置处,使用当前字体显示单个字符.  c ...

  9. Linux命令行下的vim文本编辑器

    Linux命令行下的vim文本编辑器 下面这个网站的地址讲解的非成分清楚!!!! http://blog.csdn.net/niushuai666/article/details/7275406 学习 ...

随机推荐

  1. JDBC ----常用数据库的驱动程序及JDBC URL:

    常用数据库的驱动程序及JDBC URL: Oracle数据库: 驱动程序包名:ojdbc14.jar  驱动类的名字:oracle.jdbc.driver.OracleDriver  JDBC URL ...

  2. 用Python作GIS之二:STARS开发环境配置

    STARS的一般使用可以通过REGAL网页快速学习http://regionalanalysislab.org/?n=STARS再次不做详细介绍这里关注的主题是对STARS源代码分析即为使用Pytho ...

  3. EHCache 实现通用类 CacheManager

    package com.zhubaje.api.workflow.ehcache; import java.io.Serializable; import java.util.ArrayList; i ...

  4. boost安装

    虽然很多Boost组件都只有头文件,不需要编译,但是有些Boost组件,如program_options.regex等还是需要编译生成库的.考虑到目前的程序需要用到program_options.re ...

  5. 【iis错误码】IIS 服务 这些年遇到的错误码

      II 发生错误,客户端似乎有问题.例如,客户端请求不存在的页面,客户端未提供有效的身份验证信息. 400 - 错误的请求. 401 - 访问被拒绝.   -- 暴力添加everyone用户,  i ...

  6. 兼容iOS 10 资料整理笔记-b

    原文链接:http://www.jianshu.com/p/0cc7aad638d9 1.Notification(通知) 自从Notification被引入之后,苹果就不断的更新优化,但这些更新优化 ...

  7. javascript 获取父页面中元素对象方法

    父页面中: <input type="hidden" id="areaID" value="test1"> <iframe ...

  8. 【BZOJ】【3524】【POI2014】Couriers

    可持久化线段树 裸可持久化线段树,把区间第K大的rank改成num即可……(往儿子走的时候不减少) 苦逼的我……MLE了一次(N*30),RE了一次(N*10)……数组大小不会开…… 最后开成N*20 ...

  9. C# WinForm开发系列 - ZedGraph

    ZedGraph是用于创建任意数据的二维线型.条型.饼型图表的一个类库,也可以作为Windows窗体用户控件和Asp.Net网页控件.这个类库具有高度的适应性,几乎所有式样的图表都能够被创建.这个类库 ...

  10. [转载]GDI+中发生一般性错误

    注:第一次写博客,把自己遇到的问题和收集的资料记录在博客上.在开发.NET应用中,使用 System.Drawing.Image.Save 方法而导致“GDI+ 中发生一般性错误”的发生,通常有以下三 ...