cocos2d

1169次阅读  |  发布于5年以前

某次使用 cocos2d-html5 时发现,通过 cc.LabelTTF 显示的文本即使宽度超过了预设值,也不会自动换行。上网搜了下,很多人都遇到了同样的问题。

之前用 cocos2d-x 的 CCLabelTTF 没这个问题。看了下代码,在 iOS 平台上, CCLabelTTF 最终是调用 UIStringDrawing 的 drawInRect 函数,而这个函数支持设置 lineBreakMode,也就是换行模式。

接着再看 cocos2d-html5 里的 CCLabelTTF.js,发现 _updateTTF 这个函数里其实有换行逻辑,但是只处理了空格和 \n 换行:如果一行文本太长,会在最近的空格处换行;\n 则是用来强制换行的。这个策略对于英文这种单词之间有空格的语言来说是够用,但是对于中文就不合适了。

如果在创建 LabelTTF 时,字符串已按照指定宽度插入 \n 强制换行,那最终的展现结果就是我想要的。由于文本包含中文、英文、数字和符号,又很少使用等宽 字体。所以要确定指定的宽度能显示多少字符,除了不断尝试没什么好办法。

首先,我们需要获取指定文本的宽度,可以通过创建一个临时 LabelTTF 来完成:


function getStrWidth(str, fontName, fontSize) {

        var tmpLabel = cc.LabelTTF.create(str, fontName, fontSize);
        return tmpLabel.getContentSize().width;
    }

也可以用 measureText 来实现同样的功能(下面这个方案在 html5 和 iOS 的 jsb 环境都 OK,在 java 环境下会报错):


function getStrWidth(str, fontName, fontSize) {

        cc.renderContext.font = fontSize + "px " + fontName;
        return cc.renderContext.measureText(str).width;
    }

接着,就可以循环插入 \n 了。大概思路是指定一个差不多的初始值 L(可以用指定宽度 width 除以字体大小),截出 0 到 L 位置的字符串,用 getStrWidth 计算宽度,如果比我们指定的宽度 width 大,L--,继续比较;否则 L++ 继续。直到 L 个字符宽度和我们指定宽度刚好相等(很小的概率),或者 L 个字符长度不够,但 L+1 长度又多了的情况下,可以确定这一行可以放这 L 个字符。然后继续处理下一行,直至字符串结束。

实际效果和实现见 Demo 和代码。理论上,如果中英文混排的时候,应该尽可能避免把英文单词拆开,这个 Demo 没处理这种情况。效率方面我测试了下,6000 个中英文字符串以 500px 宽度,16px 字号插入 \n,用第一种方法耗时 10 几 ms,第二种才几 ms,基本都可以忽略不计。

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8