我是一个很喜欢炫耀的人,我最近解决了一个问题,所以来炫耀了~嘿嘿~
希望各位被我炫耀的同时,也把我学到的知识偷走,随便偷,不要钱哈~
在看我的帖子之前,请确保你已经看过或者掌握了这个帖子(在没有输入焦点类控件上调用输入法):
http://www.android-fans.net/forum.php?mod=viewthread&tid=38&extra=page%3D1
是这位朋友发了这个帖子之后我才得以解决这个问题的~再次感谢他~
好了,描述一下我的问题,游戏开发的过程中,很少甚至可以说是没有用到系统自带的控件~
反正我是没有用到,不知道是不是我井底之蛙了,嘿嘿~
按钮、标签、窗口、滑动窗口之类的控件,虽说实现得不是很好,但是起码还是能自己实现的。
唯独这个输入框,整晕我了,困扰了我好久~
我不知道怎么弹出输入法,就算后来我知道了,我还是不知道怎么去获取输入法的输入。
不知道有没有人有着和我一样的困扰呢?~
是不是发现我好多废话?~别着急,你还要忍受我的很多废话呢,嘻嘻~
好喇,开始~
先看截图,免得浮躁,嘻嘻:
整个例子的代码都在附件里,我的注释应该算蛮清晰的,嘿嘿,所以大家看代码就好,在这里我只是简单说几个要注意的地方~
再次提醒,记得先看懂了上面提到的那个帖子再往下看哈~
1. 首先来看看游戏的主界面,GameView里要重写一个方法:
@Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { return new XInputConnection(this, false); }
是的,这个就是上面提到的那个帖子里教我们的,重写这个方法就能监听到输入法的一些小动作,这家伙,逃不过我们的手掌的,嘿嘿~
2. 当然,必须得自己实现一个XInputConnection类,先别看代码,写看看我的解释,哈哈:
public class XInputConnection extends BaseInputConnection { public XInputConnection(View targetView, boolean fullEditor) { super(targetView, fullEditor); } @Override public boolean commitText(CharSequence text, int newCursorPosition) { /* 发送每一个输入的字符到自定义的输入框控件 */ HashMap<String, Object> map = new HashMap<String, Object>(); map.put("sChar", (String)text); GlobalClient.messageDispatch.dispatchMessage(EnumMsgDispatchType.EN_COMMIT_TEXT, map); return true; } @Override public boolean sendKeyEvent(KeyEvent event) { /* 发送键盘事件到自定义的输入框控件 */ HashMap<String, Object> map = new HashMap<String, Object>(); map.put("keyEvent", event); GlobalClient.messageDispatch.dispatchMessage(EnumMsgDispatchType.EN_SEND_KEY_EVENT, map); return super.sendKeyEvent(event); } }
这个类很简单,抓住了输入法的两个小动作,一个是输入字符,一个是软键盘的事件(可能我说错了,大概是这样的,可以纠正我错误~)。
抓住了输入字符的事件,我们就可以让自己的输入框显示这些字符,这个很重要,输入框必须得有的功能嘛~
抓住键盘事件又是做什么的呢?那大家想想,我只能输入,不能删除,那这个输入框要来做嘛?~
是的,有了键盘事件,我们就能监听到删除键,然后就能删除字符。
OK~输入框要的两个基本功能已经有条件实现了~
注意喇,别去研究两个方法的具体实现先,那只是我实现的方法,大家都可以用自己的方式去实现的~
有了杯子和水,至于怎么把水装进杯子,就因人而异了,对不对?~
3. 主角出场~我自己实现的EditText控件(只贴出部分代码):
/** * 自定义的输入框 * @author 笨木头 * */ public class XEditText implements IMessageDispatchSink, ISoldHold { public XEditText(Context _context, Point _point, Bitmap _background) { this.context = _context; this.point = _point; this.background = _background; initOnClickListener(); } public void drawMe(Canvas canvas) { /* 输入框背景 */ canvas.drawBitmap(background, point.x, point.y, paint); /* 输入框文字的坐标调整了,调整的算法是临时的,所以可以忽略 */ canvas.drawText(sText, point.x + iFontSize / 2, point.y + iFontSize / 2 + background.getHeight() / 2, paint); } @Override public void onRecv(EnumMsgDispatchType enMsgDispatchType, HashMap<String, Object> map) { switch(enMsgDispatchType) { case EN_COMMIT_TEXT: /* 输入字符 */ commitText(map); break; case EN_SEND_KEY_EVENT: /* 键盘事件 */ sendKeyEvent(map); break; } } @Override public void onClickCMD() { listener.onClick(); } @Override public void setOnClickListener(IMsgOnClickListener listener) { this.listener = listener; } /** * 输入字符 * @param map */ private void commitText(HashMap<String, Object> map) { if(map == null) { return; } String sChar = (String) map.get("sChar"); sText += sChar; } /** * 键盘事件 * @param map */ private void sendKeyEvent(HashMap<String, Object> map) { if(map == null) { return; } KeyEvent event = (KeyEvent) map.get("keyEvent"); if(event.getAction() == 1) { /* 删除字符事件 */ if(event.getKeyCode() == KeyEvent.KEYCODE_DEL) { int iLen = sText.length(); if(iLen > 0) { sText = sText.substring(0, iLen - 1); } } } } /** * 设置监听事件 */ private void initOnClickListener() { this.setOnClickListener(new IMsgOnClickListener() { @Override public void onClick() { /* 发布显示输入法的消息 */ GlobalClient.messageDispatch.dispatchMessage(EnumMsgDispatchType.EN_SHOW_IUPUT, null); } }); } }
首先,作为一个控件,肯定少不了要有一个OnClick事件咯,至于实现的方法,大家用自己的方法就好,可以不用管我的方法。
然后,XEditText里还有两个方法,一个commitText(), 大家都知道了,用来获取字符的;还有一个sendKeyEvent(), 用来删除字符的~
OK,那,输入法输入字符和删除字符的动作,是怎么告诉我的输入框的呢?我用的方法是消息派发:
XInputConnection里调用这两个方法的时候,就发布消息,告诉所有想知道这个方法的对象。
至于消息派发是什么东西,也有大部分人都懂了~
如果有还没有接触到消息派发的朋友,我以后再另开帖子写一下我的见解哈~
反正现在大家只要知道一点,输入法有了输入字符和删除字符的动作,就会调用XInputConnection 的commitText()和sendKeyEvent()方法,
而这两个方法被我们重写了,我们可以在两个方法里利用消息派发,把输入的字符和删除字符动作告诉输入框。
OK了~嘿嘿
4. 还有一点要注意的,GameView要获取了焦点之后才能弹出输入法:
/** * 显示输入法界面 */ private void showInput() { /* 要让GameView获得焦点后才能弹出输入法 */ this.requestFocus(); input.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS); }
我的唠叨到此结束喇~
最后当然要附上我的代码喇~
为了来这里炫耀,这个例子我写了一个多小时,然后这篇文字我又写了差不多一个小时,大家不要辜负我吖~嘿嘿
对了,补充一下,这个方法是可以实现输入框,但是有个问题:
部分手机在横屏的情况下,会无法显示输入法的候选栏,这个我还没有解决,如果有哪位朋友解决,请分享咯~嘿嘿
代码是为了尽量节省时间,所以有些地方是写死的:
1. 一些字符串常量没有抽离出来
2. 没有写专门管理控件的模块
3. 初始化函数堆了很多东西,有些乱
4. 坐标写死
5. 除了以上4条,如果有其他问题,一定要告诉我哈,记得咯~
源代码(CSDN上传的资源还没有验证通过,大家暂时到这个帖子里下载哈):http://www.android-fans.net/forum.php?mod=viewthread&tid=99#lastpost
CSDN的资源已经上传了,补上: http://download.csdn.net/detail/musicvs/4112154