部分关键代码与思路参考 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. Is C# a clone of a Microsoft replacement for Java?

    Is C# a clone of a Microsoft replacement for Java?Let's look at what Anders Hejlsberg Said. Hejlsber ...

  2. 1107. Social Clusters (30)

    When register on a social network, you are always asked to specify your hobbies in order to find som ...

  3. mysql 配置主从

    1.选择2个ip,1个为主,1个为从:例:主:192.168.12.76 从:192.168.12.772.在192.168.12.76的my.cnf 配置master,添加如下:(红色为添加的内容) ...

  4. redis常见性能问题和解决方案?

    Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以Master最好不要写内存快照. Master AOF持久化, ...

  5. 20145120 《Java程序设计》第3周学习总结

    20145120 <Java程序设计>第3周学习总结 教材学习内容总结 基本类型与类类型的概念 在java里使用数组和字符串 封装的概念 在java定义函数 重载的概念 static的概念 ...

  6. C#中Linq查询基本操作

    摘要:本文介绍Linq查询基本操作(查询关键字) - from 子句 - where 子句 - select子句 - group 子句 - into 子句 - orderby 子句 - join 子句 ...

  7. 在ubuntu16.04 下安装haproxy 1.5.11 做tcp负载均衡

    由于haproxy需要FQ下载,所以从csdn下载了较为新版的haproxy1.5.11,安装过程如下: 1. 解压haproxy-1.5.11.tar.gz : tar xzvf haproxy-1 ...

  8. Python的map、filter、reduce函数 [转]

    1. map函数func作用于给定序列的每个元素,并用一个列表来提供返回值. map函数python实现代码: def map(func,seq): mapped_seq = []        fo ...

  9. java 连接池的简单实现

    最近一个项目中需要自己写个连接池, 写了一个下午,挺辛苦的,但不知道会不会出问题, 所以,贴到博客上,欢迎各路大神指点 1. 配置信息: /** * */ package cn.mjorcen.db. ...

  10. Problem 1016 咒文卷轴 优先队列+前缀和+rmq

    题目链接: 题目 Problem 1016 咒文卷轴 Time Limit: 3000 mSec Memory Limit : 131072 KB 问题描述 小Y 是一个魔法师,有一天他获得了一卷神秘 ...