笨木头  2012-03-04 23:01     Android     阅读(10550)     评论(12)
转载请注明,原文地址: http://www.benmutou.com/archives/215
文章来源:笨木头与游戏开发


 我是一个很喜欢炫耀的人,我最近解决了一个问题,所以来炫耀了~嘿嘿~
希望各位被我炫耀的同时,也把我学到的知识偷走,随便偷,不要钱哈~

在看我的帖子之前,请确保你已经看过或者掌握了这个帖子(
在没有输入焦点类控件上调用输入法):
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

12 条评论
  • tianshenshangjie 2012-03-05 11:08:00

    楼主 BUG修改了么?QQ多少想交流下
    0回复
  • musicvs 2012-03-05 12:39:00

    [reply]tianshenshangjie[/reply]
    Bug还没解决呢...貌似是Android的一个小Bug?
    我QQ: 357382814 (一般晚上在线哈~)
    0回复
  • ialex32x 2012-05-03 11:35:00

    Good
    0回复
  • musicvs 2012-05-03 12:00:00

    [reply]ialex32x[/reply]
    谢谢~嘿嘿
    0回复
  • xiaomashizhu123 2012-05-03 21:03:00

    很好啊!
    0回复
  • musicvs 2012-05-03 21:27:00

    [reply]xiaomashizhu123[/reply]
    最开心的就是得到认可了~谢谢
    0回复
  • cq361106306 2012-08-24 15:51:00

    能简单介绍下如何自己实现一个button吗,不是靠继承系统控件那种,因为我想方便的用在surfaceview里面,但是不知道如何监听他,
    0回复
  • musicvs 2012-08-24 16:00:00

    [reply]cq361106306[/reply]
    你可以看看我们论坛自己组织写的一个小的游戏引擎,我负责编写控件模块,你看看?叫做AndroidFans引擎~
    http://www.android-fans.net/forum-100-1.html
    0回复
  • cq361106306 2012-08-24 16:08:00

    [reply]musicvs[/reply]
    真棒,我正在看哈哈
    0回复
  • musicvs 2012-08-24 16:17:00

    [reply]cq361106306[/reply]
    能帮上忙就好~嘿嘿
    0回复
发表评论
粤ICP备16043700号

本博客基于 BlazorAnt Design Blazor 开发