我们项目中的输入框使用的都是 EditBox , 但是 EditBox 还存在一些问题, 这里给大家分享一下我们的解决方案.
一. 字体过大
用过 EditBox 的同学都知道这样一个情况, EditBox 在创建时是无法传入字体大小的, 字体大小默认和 EditBox 的 size 一致. 如果要修改字体大小的话, 就必须有程序的参与, 十分讨厌.
而我们聪明的设计师 @大勇同学 则想到了一个非常棒的办法, 使用一张透明的9图来创建 EditBox, 后面再放置一个真实效果的 Scale9Sprite , 这样就可以实现字体比边框小很多的输入框了.
二. 多行输入
多行输入是一个很有必要的事情, 我们在写邮件, 军团公告等界面都有类似的需求, 然而 EditBox 并不能很好的支持多行输入, 不同平台间也存在差异, 一直很头疼这件事情.
然而团队中另外一位成员 @小齐同学 却用另一种十分脑洞的方案解决了这个问题, 着实让人佩服. 他的思路是这样子的:
创建一个和需求大小一致的 EditBox, 同时创建一个 LalbelTTF , 将 dimensions 属性设置为需求大小. 处理 EditBox 使之看不见, 但又能正常输入, 同时监听输入文字变化事件, 在事件中修改 LalbelTTF 的文字.
核心就是让 EditBox 承担只文字输入的功能, 而让另外一个 LalbelTTF 来承担文字显示的功能. 实现的代码如下:
1 | function EditBoxUtil.multiline(_editbox, _label, _params) |
这段代码和简单, 但背后所遇到的坑却不少, 且听我来道一道:
1. 为什么要调用 setFont
如果只是想设置字体大小, EditBox 明明有提供 setFontSize
接口, 为什么要调用 setFont
? 请看 setFontSize 实现:
1 | void EditBox::setFontSize(int fontSize) |
可以看到 setFontSize 在没有设置字体名称 _fontName
时是没有作用的.
2. 为什么要分平台来实现
在接入 android 前,我们是没有分平台实现的, 只是 setFont("Helvetica",0)
, 在 iOS 上没有任何问题, 但是在 Android 上会 catch 到 divide by zero
崩溃, 估计是某一个地方用 fontsize 做被除数了吧 , 于是 Android 上改为设置透明度.
3. Android 输入过多文字后会崩溃(OOM)
崩溃在 Cocos2dxBitmap.java
的 getPixels
函数中:1
2
3
4
5
6
7
8
9
10
11private static byte[] getPixels(final Bitmap bitmap) {
if (bitmap != null) {
final byte[] pixels = new byte[bitmap.getWidth() * bitmap.getHeight() * 4];
final ByteBuffer buf = ByteBuffer.wrap(pixels);
buf.order(ByteOrder.nativeOrder());
bitmap.copyPixelsToBuffer(buf);
return pixels;
}
return null;
}
在 new byte
这里触发了报错的原因是 Out Of Memory
异常 ! 调试发现 bitmap
的宽高惊人的达到了 12000x600
!
经过 @bin 的提醒, 发现这里可能是因为 EditBox 字体过大的原因, 因为 EditBox 会默认设置字体字体大小和 Scale9Sprite 的 PreferredSize 一直, 就可能设置字体大小为 100+ , 文字一多尺寸当然就上去了! 所以便有了这么一行:
1 | if device.platform == "android" then |
二. 屏蔽 Emoji 输入
按照要求游戏中玩家可以输入文字的地方都是不能够输入 Emoji 表情的, 原因有两点:
- 不同系统间表现存在差异
- EditBox Android 版输入确认后会变乱码
- 后台搜索玩家时不太方便
因此, 我们需要屏蔽 Emoji 表情的输入, 我们有两种做法:
- 无法输入, 弹出键盘点击表情没有反应
- 输入完成后, 游戏内点击提交时提示非法
我们采用的是第二种方案, 这个无法通过纯 lua 代码实现, 需要分平台去做.
1. iOS
修改 UIEditBoxImpl-ios.mm
文件的 shouldChangeCharactersInRange
函数:
1 | - (BOOL)textField:(UITextField *) textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string |
这段代码是我从 https://github.com/woxtu/NSString-RemoveEmoji 中提取出来的.
2. Android
Android 上的实现也很简单, 主要是需要创建一个新的 InputFilter
用来过滤 Emoji 表情. 需要修改 Cocos2dxEditBoxDialog.java
文件成员变量添加:
1 | public static InputFilter EMOJI_FILTER = new InputFilter() { |
修改 onCreate
函数 setFilters
处逻辑:
1 | if (this.mMaxLength > 0) { |
关于 Emoji 的相关修改都已经推送到了 github 上, 点击这里查看.