我是一個很喜歡炫耀的人,我最近解決了一個問題,所以來炫耀了~嘿嘿~
希望各位被我炫耀的同時,也把我學到的知識偷走,隨便偷,不要錢哈~
在看我的文章之前,請確保你已經看過或者掌握了這個文章(在沒有輸入焦點類控制項上調用IME):
http://www.android-fans.net/forum.php?mod=viewthread&tid=38&extra=page%3D1
是這位朋友發了這個文章之後我才得以解決這個問題的~再次感謝他~
好了,描述一下我的問題,遊戲開發的過程中,很少甚至可以說是沒有用到系統內建的控制項~
反正我是沒有用到,不知道是不是我井底之蛙了,嘿嘿~
按鈕、標籤、視窗、滑動視窗之類的控制項,雖說實現得不是很好,但是起碼還是能自己實現的。
唯獨這個輸入框,整暈我了,困擾了我好久~
我不知道怎麼彈出IME,就算後來我知道了,我還是不知道怎麼去擷取IME的輸入。
不知道有沒有人有著和我一樣的困擾呢?~
是不是發現我好多廢話?~別著急,你還要忍受我的很多廢話呢,嘻嘻~
好喇,開始~
先看,免得浮躁,嘻嘻:
整個例子的代碼都在附件裡,我的注釋應該算蠻清晰的,嘿嘿,所以大家看代碼就好,在這裡我只是簡單說幾個要注意的地方~
再次提醒,記得先看懂了上面提到的那個文章再往下看哈~
1. 首先來看看遊戲的主介面,GameView裡要重寫一個方法:
@Overridepublic InputConnection onCreateInputConnection(EditorInfo outAttrs) {return new XInputConnection(this, false);}
是的,這個就是上面提到的那個文章裡教我們的,重寫這個方法就能監聽到IME的一些小動作,這傢伙,逃不過我們的手掌的,嘿嘿~
2. 當然,必須得自己實現一個XInputConnection類,先別看代碼,寫看看我的解釋,哈哈:
public class XInputConnection extends BaseInputConnection {public XInputConnection(View targetView, boolean fullEditor) {super(targetView, fullEditor);}@Overridepublic 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;}@Overridepublic 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);}}
這個類很簡單,抓住了IME的兩個小動作,一個是輸入字元,一個是軟鍵盤的事件(可能我說錯了,大概是這樣的,可以糾正我錯誤~)。
抓住了輸入字元的事件,我們就可以讓自己的輸入框顯示這些字元,這個很重要,輸入框必須得有的功能嘛~
抓住鍵盤事件又是做什麼的呢?那大家想想,我只能輸入,不能刪除,那這個輸入框要來做嘛?~
是的,有了鍵盤事件,我們就能監聽到刪除鍵,然後就能刪除字元。
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);}@Overridepublic 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;}}@Overridepublic void onClickCMD() {listener.onClick();}@Overridepublic 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() {@Overridepublic void onClick() {/* 發布顯示IME的訊息 */GlobalClient.messageDispatch.dispatchMessage(EnumMsgDispatchType.EN_SHOW_IUPUT, null);}});}}
首先,作為一個控制項,肯定少不了要有一個OnClick事件咯,至於實現的方法,大家用自己的方法就好,可以不用管我的方法。
然後,XEditText裡還有兩個方法,一個commitText(), 大家都知道了,用來擷取字元的;還有一個sendKeyEvent(), 用來刪除字元的~
OK,那,IME輸入字元和刪除字元的動作,是怎麼告訴我的輸入框的呢?我用的方法是訊息派發:
XInputConnection裡調用這兩個方法的時候,就發布訊息,告訴所有想知道這個方法的對象。
至於訊息派發是什麼東西,也有大部分人都懂了~
如果有還沒有接觸到訊息派發的朋友,我以後再另開文章寫一下我的見解哈~
反正現在大家只要知道一點,IME有了輸入字元和刪除字元的動作,就會調用XInputConnection 的commitText()和sendKeyEvent()方法,
而這兩個方法被我們重寫了,我們可以在兩個方法裡利用訊息派發,把輸入的字元和刪除字元動作告訴輸入框。
OK了~嘿嘿
4. 還有一點要注意的,GameView要擷取了焦點之後才能彈出IME:
/*** 顯示IME介面*/private void showInput() {/* 要讓GameView獲得焦點後才能彈出IME */this.requestFocus();input.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);}
我的嘮叨到此結束喇~
最後當然要附上My Code喇~
為了來這裡炫耀,這個例子我寫了一個多小時,然後這篇文字我又寫了差不多一個小時,大家不要辜負我吖~嘿嘿
對了,補充一下,這個方法是可以實現輸入框,但是有個問題:
部分手機在橫屏的情況下,會無法顯示IME的候選欄,這個我還沒有解決,如果有哪位朋友解決,請分享咯~嘿嘿
代碼是為了盡量節省時間,所以有些地方是寫死的:
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