成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Android開發(fā)實(shí)例詳解之IMF

移動(dòng)開發(fā) Android
本博前面的文章介紹了Android開發(fā)環(huán)境的搭建和模擬器的常用操作。本次,將以Android Sample中經(jīng)典的SoftKeyboard項(xiàng)目為例,詳細(xì)解析Android上一個(gè)小型項(xiàng)目的開發(fā)過程和注意事項(xiàng)。

從SDK 1.5版本以后,Android就開放它的IMF(Input Method Framework),讓我們能夠開發(fā)自己的輸入法。而開發(fā)輸入法***的參考就是Android自帶的Sample-SoftKeyboard,雖然這個(gè)例子僅包含英文和數(shù)字輸入,但是它本身還算完整和清楚,對(duì)我們開始Android開發(fā)實(shí)戰(zhàn)有很大幫助。

一、IMF 簡(jiǎn)介

一個(gè)IMF結(jié)構(gòu)中包含三個(gè)主要的部分:

input method manager:管理各部分的交互。它是一個(gè)客戶端API,存在于各個(gè)應(yīng)用程序的context中,用來溝通管理所有進(jìn)程間交互的全局系統(tǒng)服務(wù)。

input method(IME):實(shí)現(xiàn)一個(gè)允許用戶生成文本的獨(dú)立交互模塊。系統(tǒng)綁定一個(gè)當(dāng)前的輸入法。使其創(chuàng)建和生成,決定輸入法何時(shí)隱藏或者顯示它的UI。同一時(shí)間只能有一個(gè)IME運(yùn)行。

client application:通過輸入法管理器控制輸入焦點(diǎn)和IME的狀態(tài)。一次只能有一個(gè)客戶端使用IME。

1 、InputManager

由UI控件(View,TextView,EditText等)調(diào)用,用來操作輸入法。比如,打開,關(guān)閉,切換輸入法等。

它是整個(gè)輸入法框架(IMF)結(jié)構(gòu)的核心API,處理應(yīng)用程序和當(dāng)前輸入法的交互。可以通過Context.getSystemService()來獲取一個(gè)InputMethodManager的實(shí)例。

在開發(fā)過程中,最基礎(chǔ)最重要的就是養(yǎng)成閱讀API的習(xí)慣。優(yōu)秀的程序員要養(yǎng)成把自己關(guān)在小黑屋里,斷絕與外界的聯(lián)網(wǎng)和聯(lián)系,僅僅靠自己電腦中的開發(fā)環(huán)境和API文檔,以及漂亮女仆送來的每天三頓飯,寫出優(yōu)秀的程序。這個(gè)在武俠小說中叫閉關(guān),在軟件開發(fā)中叫Clean Room,哈哈。

Android的API文檔在:%SDK_ROOM%/docs/reference/index.html,

InputManager類的位置:%SDK_ROOM%/docs/reference/android/view/inputmethod/InputMethodManager.html

由于,該類跟本次要講的Sample關(guān)系不大,這里就不詳細(xì)分析,請(qǐng)各位自行閱讀API doc吧。

2 、InputMethodService

包括輸入法內(nèi)部邏輯,鍵盤布局,選詞等,最終把選出的字符通過commitText提交出來。實(shí)現(xiàn)輸入法的基礎(chǔ)就是名為InputMethodService的類,比如你要實(shí)現(xiàn)一個(gè)谷歌輸入法,就是要extends本類。我們接下來要學(xué)習(xí)的SoftKeyboard Sample也是extends本類。InputMethodService類的位置在:%SDK_ROOM%/docs/reference/android/inputmethodservice/InputMethodService.html

InputMethodService是InputMethod的一個(gè)完整實(shí)現(xiàn),你可以再在其基礎(chǔ)上擴(kuò)展和定制。它的主要方法如下:

◆onInitializeInterface() 顧名思義,它在初始化界面的時(shí)候被調(diào)用,而一般是由于配置文件的更改導(dǎo)致該函數(shù)的執(zhí)行

◆onBinndInput() 它在另外的客戶端和該輸入法連接時(shí)調(diào)用

◆onStartInput() 非常重要的一個(gè)回調(diào),它在編輯框中用戶已經(jīng)開始輸入的時(shí)候調(diào)用。比如,當(dāng)點(diǎn)擊一個(gè)輸入框,我們需要根據(jù)這個(gè)輸入框的信息,設(shè)置輸入法的一些特性,這個(gè)在Sample中很有體會(huì)。

◆onCreateInputView() 返回一個(gè)層次性的輸入視圖,而且只是在這個(gè)視圖***次顯示的時(shí)候被調(diào)用

◆onCreateCandidatesView() 同onCreateInputView(),只不過創(chuàng)建的是候選框的視圖。

◆onCreateExtractTextView() 比較特殊,是在全屏模式下的一個(gè)視圖。

◆onStartInputView() 在輸入視圖被顯示并且在一個(gè)新的輸入框中輸入已經(jīng)開始的時(shí)候調(diào)用。

基本上輸入法的定制,都是圍繞在這個(gè)類來實(shí)現(xiàn)的,它主要提供的是一個(gè)基本的用戶界面框架(包括輸入視圖,候選詞視圖和全屏模式),但是這些都是要實(shí)現(xiàn)者自己去定制的。這里的實(shí)現(xiàn)是讓所有的元素都放置在了一個(gè)單一的由InputMethodService來管理的窗口中。它提供了很多的回調(diào)API,需要我們自己去實(shí)現(xiàn)。一些默認(rèn)的設(shè)置包括:

◆軟鍵盤輸入視圖,它通常都是被放置在屏幕的下方。

◆候選詞視圖,它通常是放置在輸入視圖的上面。

◆當(dāng)我們輸入的時(shí)候,需要改變應(yīng)用程序的界面來適應(yīng)這些視圖的放置規(guī)則。比如在Android上面輸入,編輯框會(huì)自動(dòng)變形騰出一個(gè)軟鍵盤的位置來。

兩個(gè)非常重要的視圖:

1. 軟輸入視圖。是與用戶交互的主要發(fā)生地:按鍵,畫圖或者其他的方式。通常的實(shí)現(xiàn)就是簡(jiǎn)單的用一個(gè)視圖來處理所有的工作,并且在調(diào)用 onCreateInputView()的時(shí)候返回一個(gè)新的實(shí)例。通過調(diào)用系統(tǒng)的onEvaluateInputViewShow()來測(cè)試是否需要顯示輸入視圖,它是系統(tǒng)根據(jù)當(dāng)前的上下文環(huán)境來實(shí)現(xiàn)的。當(dāng)輸入法狀態(tài)改變的時(shí)候,需要調(diào)用updateInputViewShown()來重新估計(jì)一下。

2. 候選詞視圖。當(dāng)用戶輸入一些字符之后,輸入法可能需要提供給用戶一些可用的候選詞的列表。這個(gè)視圖的管理和輸入視圖不大一樣,因?yàn)檫@個(gè)視圖是非常的短暫的,它只是在有候選詞的時(shí)候才會(huì)被顯示。可以用setCandidatesViewShow()來設(shè)置是否需要顯示這個(gè)視圖。正是因?yàn)檫@個(gè)顯示的頻繁性,所以它一般不會(huì)被銷毀,而且不會(huì)改變當(dāng)前應(yīng)用程序的視圖。

***,關(guān)于文本的產(chǎn)生,這是一個(gè)IME的最終目的。它通過InputConnection來鏈接IME和應(yīng)用程序的:能夠直接產(chǎn)生想要的按鍵信息,甚至直接在候選和提交的文本中編輯。當(dāng)用戶在不同的輸入目標(biāo)之間切換的時(shí)候,IME會(huì)不斷的調(diào)用onFinishInput() 和 onStartInput()。在這兩個(gè)函數(shù)中,需要反復(fù)做的就是復(fù)位狀態(tài),并且應(yīng)對(duì)新的輸入框的信息。

以上是一個(gè)輸入法的最基本的介紹,下面將根據(jù)Sample中的SoftKeyboard來說明這些問題。

二、創(chuàng)建Eclipse工程

這里使用***版本的Android SDK 2.3.3下的SoftKeyboard Sample來創(chuàng)建工程,其實(shí),從1.5版本,該Sample就已經(jīng)存在了。同時(shí),由于SoftKeyboard會(huì)使人誤解為KeyBoard的子類,這里特別改名為InputMethodServiceSample,更符合其功能和特性。

 創(chuàng)建Eclipse工程

點(diǎn)擊Finish,完成項(xiàng)目的創(chuàng)建,可以看到項(xiàng)目工程結(jié)構(gòu)如下:

  創(chuàng)建Eclipse工程

在Android SDK 2.3.3模擬器上運(yùn)行本Sample,需要在Setting中選擇使用本Sample,需要在Language&keyboard中選中本Sample的名稱。

 創(chuàng)建Eclipse工程

創(chuàng)建Eclipse工程

當(dāng)嘗試選中Sample Soft Keyboard時(shí),Android會(huì)出現(xiàn)安全提示。IME的確要選擇自己信任的,因?yàn)樗梢允占陀涗浰心愕妮斎耄@個(gè)特性如果被有心人利用會(huì)很恐怖。

選中Sample Soft Keyboard作為我們的輸入法之后,進(jìn)入需要輸入法的地方,這里以短信界面作為范例,在輸入框中長(zhǎng)按,會(huì)出現(xiàn)“編輯文本”選單,點(diǎn)擊“輸入法”即可進(jìn)入當(dāng)前輸入界面的輸入法選擇框。就可以使用輸入法切換到本輸入法看到它的keyboard。

 創(chuàng)建Eclipse工程

創(chuàng)建Eclipse工程

之后就可以看到Soft keyboard鍵盤如下:

創(chuàng)建Eclipse工程

三、配置和資源文件解析

除去源代碼將在后文統(tǒng)一分析之外,這里介紹下配置和資源文件。

1. AndroidMainifest.xml

每個(gè)Android應(yīng)用都會(huì)有的配置描述文件。在這里,Sample把自己聲明成了服務(wù),而且綁定在了輸入法之上。它的intent-filter是直接用的InputMethod接口,這也是所有的輸入法的接口。

2. res 目錄

放置resource,即資源文件,里面蠻多東西的,具體如下。

(1) drawable目錄,放置的是圖標(biāo)文件。

(2) values目錄,包含strings.xml以及一些自定義的類型和值的xml文件。

strings.xml

― ime_name 定義了該輸入法的名字

― word_separators 詞的分隔符,即輸入過程中可能用來表示一個(gè)詞輸入完成的符號(hào),比如空格,標(biāo)點(diǎn)等等)

― label_xx_key 為軟鍵盤定義確認(rèn)鍵的標(biāo)簽。在后面代碼解析中可以看到,程序會(huì)根據(jù)輸入框的信息來設(shè)置EnterKey的圖標(biāo)或者標(biāo)簽。如:在一個(gè)網(wǎng)址上面輸入,就會(huì)顯示一個(gè)搜索的圖標(biāo),而在編輯短信時(shí),如果在收信人寫,那么EnterKey就是Next標(biāo)簽,用來直接跳到短信正文部分。

dimens.xml,定義軟鍵盤的尺寸信息,包括鍵高(key_height),候選詞字體的高度(candidate_font_height),候選詞垂直間隙(candidate_vertical_padding)。

color.xml,定義候選詞的背景顏色,比如正常(candidate_normal),推薦(candidate_recommended),背景(candidate_background)和其它(candidate_other)等顏色。

(3) layout目錄,保存布局配置文件。這里只有一個(gè)配置文件:input.xml,它定義的是輸入視圖的信息,包括id(android:id="@+id/keyboard"),放置在屏幕下方(android:layout_alignParentBottom="true"),水平***填充(android:layout_width="match_parent"),垂直包含子內(nèi)容(android:layout_height="wrap_content")。

(4) xml目錄,文件如下:

method.xml,為搜索管理提供配置信息。

qwerty.xml,英文字符的全鍵盤布局文件。定義很直觀,很容易就可以看懂。

symbols_shift.xml和symbols.xml,是標(biāo)點(diǎn)字符的全鍵盤布局文件。

四、源代碼解析

(一)概述

從InputMethodServiceSample項(xiàng)目可以看出實(shí)現(xiàn)一個(gè)輸入法至少需要CandidateView, LatinKeyboard, LatinKeyboardView,SoftKeyboard這四個(gè)文件:

◆CandidateView負(fù)責(zé)顯示軟鍵盤上面的那個(gè)候選區(qū)域。

◆LatinKeyboard負(fù)責(zé)解析并保存鍵盤布局,并提供選詞算法,供程序運(yùn)行當(dāng)中使用。其中鍵盤布局是以XML文件存放在資源當(dāng)中的。比如我們?cè)跐h字輸入法下,按下b、a兩個(gè)字母。LatinKeyboard就負(fù)責(zé)把這兩個(gè)字母變成爸、把、巴等顯示在CandidateView上。

◆LatinKeyboardView負(fù)責(zé)顯示,就是我們看到的按鍵。它與CandidateView合起來,組成了InputView,就是我們看到的軟鍵盤。

◆SoftKeyboard繼承了InputMethodService,啟動(dòng)一個(gè)輸入法,其實(shí)就是啟動(dòng)一個(gè)InputMethodService,當(dāng)SoftKeyboard輸入法被使用時(shí),啟動(dòng)就會(huì)啟動(dòng)SoftKeyboard這個(gè)Service。

(二)LatinKeyboard.java

軟鍵盤類,直接繼承了Keyboard類,并定義一個(gè)xml格式的Keyboard的布局,來實(shí)現(xiàn)一個(gè)輸入拉丁文的鍵盤。這里只是創(chuàng)建一個(gè)鍵盤對(duì)象,并不對(duì)具體的布局給出手段。

為了更好的理解LatinKeyboard類,這里簡(jiǎn)單介紹一下Keyboard類。Keyboard可以載入一個(gè)用來顯示鍵盤布局的xml來初始化自己,并且可以保存這些鍵盤的鍵的屬性。他有三個(gè)構(gòu)造函數(shù):

◆Keyboard(Context context, int xmlLayoutResId),用語境和xml資源id索引xml文件來創(chuàng)建。

◆Keyboard(Context context, int xmlLayoutResId, int modeId),這個(gè)和上面差不多,只不過多了一個(gè)modeld。

◆Keyboard(Context context, int layoutTemplateResId, CharSequence characters, int columns, int horizontalPadding),這個(gè)比較復(fù)雜,用一個(gè)空xml布局模板創(chuàng)建一個(gè)鍵盤,然后用指定的characters按照從左往右,從上往下的方式填滿這個(gè)模板。

本文件源碼前面完全繼承keyboard,直接用了父類構(gòu)造函數(shù)進(jìn)行初始化。

這里因?yàn)橹貙懥薑eyboard類的createKeyFromXml(Resources res, Row parent, int x, int y, XmlResourceParser parser),為了要返回一個(gè)Key對(duì)象,干脆直接創(chuàng)建LatinKey對(duì)象好了。從這里我們能看出面向?qū)ο蠛褪褂每蚣艿囊蟆?/p>

接著,本文件重載了一個(gè)createKeyFromXml的函數(shù),這是一個(gè)回調(diào)函數(shù),它在鍵盤描繪鍵的時(shí)候調(diào)用,從一個(gè)xml資源文件中載入一個(gè)鍵,并且放置在(x,y)坐標(biāo)處。它還判斷了該鍵是否是回車鍵,并保存起來。在這里,為了要返回一個(gè)Key對(duì)象,于是直接創(chuàng)建內(nèi)部類的LatinKey對(duì)象。從這里我們能看出面向?qū)ο蠛褪褂每蚣艿囊蟆?/p>

此外,還有一個(gè)函數(shù)是:setImeOptions,它是根據(jù)編輯框的當(dāng)前信息,來為這個(gè)鍵盤的回車鍵設(shè)置適當(dāng)?shù)臉?biāo)簽。輸入框的不同,會(huì)產(chǎn)生不同的回車鍵的label或者icon。在這個(gè)函數(shù)中,有一個(gè)技巧是用了一些imeOption的位信息,比如IME_MASK_ACTION等等。主要是查看的EditorInfo的Action信息,這里有:

◆IME_ACTION_GO: go操作,將用戶帶入到一個(gè)該輸入框的目標(biāo)的動(dòng)作。確認(rèn)鍵將不會(huì)有icon,只有l(wèi)abel: GO

◆IME_ACTION_NEXT: next操作,將用戶帶入到該文本框的寫一個(gè)輸入框中。如: 編輯短消息的時(shí)候,內(nèi)容就是收件人手機(jī)號(hào)碼框的next文字域。它也只是一個(gè)NEXT label就行了。

◆IME_ACTION_SEARCH: search操作,默認(rèn)動(dòng)作就是搜索。如: 在URL框中輸入的時(shí)候,默認(rèn)的就是search操作,它提供了一個(gè)像放大鏡一樣的icon。

◆IME-ACTION_SEND: send操作,默認(rèn)動(dòng)作就是發(fā)送當(dāng)前的內(nèi)容。如: 短消息的內(nèi)容框里面輸入的時(shí)候,后面通常就是一個(gè)發(fā)送操作。它也是只提供一個(gè)Label:SEND

◆DEFAULT: 默認(rèn)情況下表示文本框并沒有什么特殊的要求,所以只需要設(shè)置return的icon即可。

***,它還定義了一個(gè)內(nèi)部類——LatinKey,它直接繼承了Key,來定義一個(gè)單獨(dú)的鍵,它唯一重載的函數(shù)是isInside(int x , int y ),用來判斷一個(gè)坐標(biāo)是否在該鍵內(nèi)。它重載為判斷該鍵是否是CANCEL鍵,如果是則把Y坐標(biāo)減少10px,按照他的解釋是用來還原這個(gè)可以關(guān)掉鍵盤的鍵的目標(biāo)區(qū)域。

(三)LatinKeyboardView.java

這里就是個(gè)View,自然也繼承自View,因?yàn)榍懊鎰?chuàng)建的鍵盤只是一個(gè)概念,并不能實(shí)例出來一個(gè)UI,所以需要借助于一個(gè)VIEW類來進(jìn)行繪制。這個(gè)類簡(jiǎn)單的繼承了KeyboardView類,然后重載了一個(gè)動(dòng)作方法,就是onLongPress。

它在有長(zhǎng)時(shí)間按鍵事件的時(shí)候會(huì)調(diào)用,首先判斷這個(gè)按鍵是否是CANCEL鍵,如果是的話就通過調(diào)用 KeyboardView被安置好的OnKeyboardActionListener對(duì)象,給鍵盤發(fā)送一個(gè)OPTIONS鍵被按下的事件。它是用來屏蔽CANCEL鍵,然后發(fā)送了一個(gè)未知的代碼的鍵。

(四)CandidateView.java

CandidateView是一個(gè)候選字顯示view,它提供一個(gè)候選字選擇的視圖,直接繼承于View類即可。在我們輸入字符時(shí),它應(yīng)該能根據(jù)字符顯示一定的提示,比如拼音同音字啊,聯(lián)想的字啊之類的。

1. 先看它定義了那些重要變量:

◆mService: candidateView的宿主類,即該view是為什么輸入法服務(wù)的。

◆mSuggestions: 建議。比如說當(dāng)我們輸入一些字母之后輸入法希望根據(jù)輸入來進(jìn)行聯(lián)想建議。

◆mSelectedIndex: 用戶選擇的詞的索引。

◆mSelectionHighlight: 描繪選擇區(qū)域高亮的類。

◆mTypedWordValid: 鍵入的word是否合法正確。

◆mBgPadding: 背景填充區(qū)域。

◆mWordWidth: 每個(gè)候選詞的寬度。

◆mWordX:每個(gè)候選詞的X坐標(biāo)。有了這兩個(gè)變量,就能夠在屏幕上準(zhǔn)確的繪制出該候選鍵。

◆mColor*:定義了各種顏色。

◆mPaint: 一個(gè)繪圖類,后面會(huì)用到

◆mVerticalPadding: 垂直填充區(qū)域。

◆mTargetScrollX: 目標(biāo)滾動(dòng)的橫坐標(biāo),即要將目標(biāo)滾動(dòng)到何處。

◆mTotalWidth: 總的寬度

◆mGestureDetector: 聲明一個(gè)手勢(shì)監(jiān)測(cè)器

GestureDetector對(duì)象似乎很少見,讓我們了解一下android.view.GestureDetector。這是一個(gè)與動(dòng)作事件相關(guān)的類,可以用來檢測(cè)各種動(dòng)作事件,這里稱之為:手勢(shì)監(jiān)測(cè)器。它的回調(diào)函數(shù)是GestureDetector.OnGestureListener,在動(dòng)作發(fā)生時(shí)執(zhí)行,而且只能在觸摸時(shí)發(fā)出,用滾動(dòng)球無效。要使用這個(gè)通常要先建立一個(gè)對(duì)象,如同代碼里體現(xiàn)的,然后設(shè)置GestureDetector.OnGestureListener 同時(shí)在 onTouchEvent(MotionEvent)中寫入動(dòng)作發(fā)生要執(zhí)行的代碼。

2. 構(gòu)造函數(shù),主要是對(duì)一些變量的初始化工作。

首先初始化了mSelectionHighlight,這是一個(gè)drawable對(duì)象,并利用drawable的setState方法設(shè)置這個(gè)drawable的初始狀態(tài)。同時(shí)在res目錄下加入一個(gè)color.xml文件來定義用到的所有顏色資源,然后用R索引,這些資源可以被加入到自己的R.java的內(nèi)容里,可以直接引用。 剩下的內(nèi)容就是初始化背景,選中,未選中時(shí)的view的背景顏色,這里都是在前面color.xml內(nèi)定義的了。用這樣的方式獲得:

Resources r = context.getResources();

獲得當(dāng)前資源對(duì)象的方法。

setBackgroundColor(r.getColor(R.color.candidate_background));

然后初始化了一個(gè)手勢(shì)檢測(cè)器(gesturedetector),它的Listener重載了一個(gè)方法,就是onScroll,這個(gè)類是手勢(shì)檢測(cè)器發(fā)現(xiàn)有scroll動(dòng)作的時(shí)候觸發(fā)。在這個(gè)函數(shù)里,主要是進(jìn)行滑動(dòng)的判斷。

這里用到了很多view下的方法:getScrollX();getWidth();scrollTo(sx, getScrollY());invalidate();我們分別解釋如下:

◆getScrollX():獲得滾動(dòng)后view的橫坐標(biāo)

◆scrollTo():滾動(dòng)到目標(biāo)坐標(biāo)

◆getScrollY():獲得滾動(dòng)后view的縱坐標(biāo)

◆invalidate():使view重畫

在這里,distanceX是上次調(diào)用onscroll后滾動(dòng)的X軸距離。假設(shè)這個(gè)view之前沒有被滾動(dòng)過,***次滾動(dòng)且坐標(biāo)在顯示區(qū)域內(nèi),sx=getScrollX()+distanceX,則view就scrollTo這個(gè)位置。如果sx超過了***顯示寬度,則scrollTo就滾想原先sx處,也就是不動(dòng)。也就是說:系統(tǒng)滾動(dòng)產(chǎn)生一個(gè)慣性的感覺,當(dāng)你把view實(shí)際到了X坐標(biāo)點(diǎn),系統(tǒng)再給你加一個(gè)distanceX,這個(gè)distanceX不是兩個(gè)動(dòng)作之間的距離,應(yīng)該是上一個(gè)滾動(dòng)動(dòng)作的停止點(diǎn)和本次滾動(dòng)動(dòng)作的停止點(diǎn)之間的距離,這個(gè)距離系統(tǒng)自己算,我們不用管,只要到了***邊界,view就不再滾動(dòng),或者說是原地滾動(dòng)。

接下來:

◆setHorizontalFadingEdgeEnabled(true);// 設(shè)置view在水平滾動(dòng)時(shí),水平邊是否淡出。

◆setWillNotDraw(false);// view不自己繪制自己

◆setHorizontalScrollBarEnabled(false);// 不設(shè)置水平滾動(dòng)條

◆setVerticalScrollBarEnabled(false);// 不設(shè)置垂直滾動(dòng)條

3. setService 是設(shè)置宿主輸入法。

4. computeHorizontalScrollRange ,表示這個(gè)view的水平滾動(dòng)區(qū)域,返回的是候選視圖的總體寬度。

5. onMeasure ,重載自view類,在布局階段被父視圖所調(diào)用。比如當(dāng)父視圖需要根據(jù)其子視圖的大小來進(jìn)行布局時(shí),就需要回調(diào)這個(gè)函數(shù)來看該view的大小。當(dāng)調(diào)用這個(gè)函數(shù)時(shí)必須在內(nèi)部調(diào)用setMeasureDimension來對(duì)寬和高進(jìn)行保存,否則將會(huì)有異常出現(xiàn)。這里重載它是為了系統(tǒng)檢測(cè)要繪制的字符區(qū)的大小,因?yàn)樽煮w可能有大小,應(yīng)根據(jù)字體來。它首先計(jì)算自己的期望的寬度,調(diào)用resolveSize來看是否能夠得到50px的寬度;然后是計(jì)算想要的高度,根據(jù)字體和顯示提示區(qū)的padding來確定。

6. onDraw ,view的主要函數(shù),每個(gè)view都必須重寫這個(gè)函數(shù)來繪制自己。它提供了一塊畫布,如果為空,則直接調(diào)用父類來畫。

在這里的內(nèi)部邏輯大概如下:

判斷是否有候選詞,沒有的話就不用繪制。

初始化背景的填充區(qū)域,直接view的背景中得到即可。

對(duì)于每一個(gè)候選詞,得到其文本,然后計(jì)算其寬度,然后再加上兩邊的空隙。

判斷是否選擇了當(dāng)前詞:觸摸的位置+滾動(dòng)了的位置。如果是在當(dāng)前詞的左邊到右邊之間,則將高亮區(qū)域繪制在畫布上面,高亮區(qū)域設(shè)置的大小即為當(dāng)前詞的大小,并且保存被選詞的索引。

將文本繪制在這個(gè)候選詞的畫布上面,它進(jìn)行了一個(gè)判斷,判斷哪個(gè)才是推薦詞。默認(rèn)情況下是候選詞的***個(gè)詞,但是它判斷***個(gè)詞是否是合法的,如果是,則***個(gè)詞是候選詞,否者第二個(gè)詞才是候選粗,然后進(jìn)行繪制。

繪制一條線,來分割各個(gè)候選詞。上面提到的總共的寬度在所有的詞都繪制出來之后,就能夠得到了。

判斷目標(biāo)滾動(dòng)是否是當(dāng)前的,不是就需要滾動(dòng)過去。

7. scrollToTarget ,滾到到目標(biāo)區(qū)域。得到當(dāng)前值,然后加上一個(gè)滾動(dòng)距離,看是否超過并進(jìn)行相應(yīng)調(diào)整,之后滾動(dòng)到相應(yīng)坐標(biāo)。

8. setSuggestions ,設(shè)置候選詞,之后進(jìn)行繪制。

9. onTouchEvent ,觸摸事件產(chǎn)生時(shí)調(diào)用。首先判斷是否為gesturedetector監(jiān)聽的動(dòng)作,如果不是就進(jìn)行下面處理。初始化動(dòng)作,把發(fā)生的動(dòng)作記錄下來,點(diǎn)觸的坐標(biāo)也記錄下來。然后,根據(jù)動(dòng)作類型分類反應(yīng):

◆向下:沒動(dòng)作;

◆移動(dòng):如果是向左移動(dòng)就要手動(dòng)的選擇候選詞;

◆向上:需要手動(dòng)選擇候選詞。

10. takeSuggestionAt ,選擇在坐標(biāo)x處的詞,這個(gè)處理的是用戶輕輕點(diǎn)擊鍵盤,也就是選擇候選詞。

11. removeHighlight ,去除高亮顯示。

(五)SoftKeyboard.java

整個(gè)輸入法的總體的框架,包括什么時(shí)候創(chuàng)建,什么時(shí)候顯示輸入法,和怎樣和文本框進(jìn)行通訊等等。上面的文件,都是為了這個(gè)類服務(wù)的。總體來說,一個(gè)輸入法需要的是一個(gè)輸入視圖,一個(gè)候選詞視圖,還有一個(gè)就是和應(yīng)用程序的鏈接。

基本時(shí)序圖如下:

 基本時(shí)序圖

輸入法在Android中的本質(zhì)就是一個(gè)Service,假設(shè)用戶剛剛啟動(dòng)Android,用戶移動(dòng)焦點(diǎn)***進(jìn)入文本編輯框時(shí),Android便會(huì)通知Service開始進(jìn)行初始化工作。于是便有了如圖中的一系列動(dòng)作。

追根溯源,onCreate方法繼承至Service類,其意義和其他Service的是一樣的。Sample在這里,做了一些非UI方面的初始化,即字符串變量詞匯分隔符的初始化。

接下來執(zhí)行onInitializeInterface,這里是進(jìn)行UI初始化的地方,創(chuàng)建以后和配置修改以后,都會(huì)調(diào)用這個(gè)方法。Sample在這里對(duì)Keyboard進(jìn)行了初始化,從XML文件中讀取軟鍵盤信息,封裝進(jìn)Keyboard對(duì)象。

第三個(gè)執(zhí)行的就是onStartInput方法,在這里,我們被綁定到了客戶端,接收所有關(guān)于編輯對(duì)象的詳細(xì)信息。

第四個(gè)執(zhí)行的方法是onCreateInputView,在用戶輸入的區(qū)域要顯示時(shí),這個(gè)方法由框架調(diào)用,輸入法***顯示時(shí),或者配置信息改變時(shí),該方法就會(huì)被執(zhí)行。在該方法中,對(duì)inputview進(jìn)行初始化:讀取布局文件信息,設(shè)置onKeyboardActionListener,并初始設(shè)置 keyboard。

第五個(gè)方法是onCreateCandidatesView,在要顯示候選詞匯的視圖時(shí),由框架調(diào)用。和onCreateInputView類似。在這個(gè)方式中,對(duì)candidateview 進(jìn)行初始化。

第六個(gè)方法,也是***一個(gè)方法,即onStartInputView,正是在這個(gè)方法中,將inputview和當(dāng)前keyboard重新關(guān)聯(lián)起來。

在上面的六個(gè)方法中,onCreateInputView和onCreateCandidatesView兩個(gè)方法只有在初始化時(shí)才會(huì)執(zhí)行一次,除非有配置信息發(fā)生改變。那么究竟什么是配置信息發(fā)生改變呢?在看InputMethodService的API文檔時(shí),可以看到有一個(gè)方法onConfigurationChanged,根據(jù)文檔解釋,這個(gè)方法主要負(fù)責(zé)配置更改的情況。在示例中,其沒有override這個(gè)方法,但是在android源碼包中的PinyinIME中,有使用這個(gè)方法,有興趣的朋友可以在看完SoftKeyboard Sample之后,看看PinyinIME的源碼。

關(guān)于本類中其它的一些方法,由于比較直觀,就不進(jìn)行講解了,感興趣的朋友可以參考《android sdk中 softkeyboard的自己解析(4) 》。

五、輸入法調(diào)試

通過使用調(diào)試模式加斷點(diǎn)的方式,有助于我們更好的理解輸入法的時(shí)序和每個(gè)類及其方法的功能和調(diào)用持續(xù)。

這里使用Eclipse的DDMS透視圖進(jìn)行調(diào)試,具體介紹參考《用Eclipse開發(fā)和調(diào)試Android應(yīng)用程序 》

首先切換到DDMS模式,在這個(gè)模式下面,DDMS將鏈接到正在運(yùn)行的手機(jī)或模擬器,并且能夠提取手機(jī)上面的各種信息,比如線程,還有各個(gè)正在后臺(tái)運(yùn)行的服務(wù)等等。點(diǎn)擊工具條上的“Debug selected Process”,就能夠?qū)⒄{(diào)試器植入到這個(gè)服務(wù)上面。

  DDMS模式

之后切換到debug模式,就會(huì)發(fā)現(xiàn)調(diào)試器已經(jīng)鏈接到了這個(gè)模擬器,然后就可以像調(diào)試普通的程序一樣調(diào)試這個(gè)輸入法了。

  debug模式

通過debug模式,我們可以發(fā)現(xiàn),輸入法首先執(zhí)行的onCreateInputView-> onCreateCandidatesView,而在這個(gè)時(shí)候,這個(gè)輸入法的界面一點(diǎn)兒都還沒有顯現(xiàn)出來。當(dāng)我們?cè)谝粋€(gè)輸入框中點(diǎn)擊鼠標(biāo)時(shí),系統(tǒng)會(huì)產(chǎn)生一個(gè)事件,最開始就被輸入法捕獲,然后再將控制權(quán)交給這個(gè)輸入法。另外,切換對(duì)象的時(shí)候,輸入法總是認(rèn)為是一次輸入的結(jié)束,然后進(jìn)行一系列的reset工作。所有的鍵盤等事件,都會(huì)首先傳遞給輸入法,所以,如果一個(gè)按鍵事件不是我們所能夠處理的問題,我們需要將這個(gè)事件繼續(xù)傳遞下去,而不要丟棄了,因?yàn)檫@可能是別的控件的事情。

在發(fā)送消息的界面,在輸入完TO某人之后,點(diǎn)擊content輸入框,首先調(diào)用的是onFinishInput,也就是結(jié)束上一次的輸入,準(zhǔn)備這次的輸入。之后調(diào)用的是onStartInputView,讓界面顯示出來。接著調(diào)用onStartInput,表示開始正式的輸入。在這過程中,要完成根據(jù)不同的輸入框,選擇不同的鍵盤,當(dāng)你輸入一個(gè)鍵,首先觸發(fā)的是onKey回調(diào),在這里要判斷是輸入的普通字符,還是控制性的字符,比如刪除,返回等等。比如這里輸入一個(gè) 'g',然后會(huì)調(diào)用處理普通字符的函數(shù)handleCharacter。這里的策略就是,輸入一個(gè)普通字符,就將Composing增加,并且更新這個(gè)候選詞的列表。這里有一個(gè)很微妙的開關(guān),就是mPrediction,它就是判斷是否是需要保存這個(gè)Composing。在比如說URL框中輸入的時(shí)候,就會(huì)置這個(gè)開關(guān)為關(guān),直接將鍵入的輸入到文本框中去。

為了測(cè)試所有的函數(shù),你必須想出一種輸入方式,讓每個(gè)函數(shù)你都能執(zhí)行到,那你就能夠看清楚輸入法的本來面目。

請(qǐng)各位朋友自己試試,對(duì)閱讀和理解源代碼的流程、時(shí)序和生命周期很有好處。也可以方便的找到自己的代碼的bug。

六、輸入法的調(diào)用

希望從一個(gè)View上調(diào)用輸入法和接收輸入法傳過來的字符串,可以通過調(diào)用EditText這個(gè)widget。但是,如果要做出很炫很個(gè)性的輸入法,就必須自己去和EditText一樣連接輸入法,介紹如下:

首先,定義一個(gè)繼承自BaseInputConnection的類。前文提到過,輸入法是通過commitText來提交選中字符。

  1. public class MyBaseInputConnection extends BaseInputConnection{   
  2.  
  3. public MyBaseInputConnection(View targetView, boolean fullEditor) {   
  4.  
  5. super(targetView, fullEditor);   
  6.  
  7. }   
  8.  
  9. public static String tx="";   
  10.  
  11. //輸入法程序就是通過調(diào)用這個(gè)方法把最終結(jié)果輸出來的   
  12.  
  13. @Override   
  14.  
  15. public boolean commitText(CharSequence text, int newCursorPosition) {   
  16.  
  17. tx = text.toString();   
  18.  
  19. return true;   
  20.  
  21. }   
  22.  
  23. }   

BaseInputConnection相當(dāng)于一個(gè)InputMethodService和View之間的一個(gè)通道。每當(dāng)InputMethodService產(chǎn)生一個(gè)結(jié)果時(shí),都會(huì)調(diào)用BaseInputConnection的commitText方法,把結(jié)果傳遞出來。

之后,采用如下方式,呼出輸入法,并且把自定義的BaseInputConnection通道傳遞給InputMethodService。

  1. public class MyView extends XXView ...{   
  2.  
  3. //得到InputMethodManager   
  4.  
  5. InputMethodManager input = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);   
  6.  
  7. //定義事件處理器   
  8.  
  9. ResultReceiver receiver = new ResultReceiver(new Handler() {   
  10.  
  11. public void handleMessage(Message msg) {   
  12.  
  13. }   
  14.  
  15. });   
  16.  
  17. ...   
  18.  
  19. //在你想呼出輸入法的時(shí)候,調(diào)用這一句   
  20.  
  21. input.showSoftInput(this0, mRR);   
  22.  
  23. ...   
  24.  
  25. @Override   
  26.  
  27. //這個(gè)方法繼承自View。把自定義的BaseInputConnection通道傳遞給InputMethodService   
  28.  
  29. public InputConnection onCreateInputConnection(EditorInfo outAttrs) {   
  30.  
  31. return new MyBaseInputConnection(thisfalse);   
  32.  
  33. }   
  34.  
  35. }   

低級(jí)界面上面,自己調(diào)用輸入法并接收輸入法的輸出結(jié)果,就是這樣的。

【編輯推薦】

  1. Android用戶界面設(shè)計(jì):布局基礎(chǔ)
  2. Android用戶界面設(shè)計(jì):線性布局
  3. Android用戶界面設(shè)計(jì):基本按鈕
責(zé)任編輯:佚名 來源: iteye
相關(guān)推薦

2011-09-08 13:11:07

Android Wid實(shí)例

2013-01-06 12:23:59

Android開發(fā)SQLite數(shù)據(jù)庫

2013-05-21 11:26:49

Android游戲開發(fā)Sensor感應(yīng)

2010-08-04 10:17:17

Android開發(fā)WebView組件

2013-05-21 09:56:15

2013-05-20 17:51:47

Android游戲開發(fā)SurfaceView

2011-08-02 11:07:42

iOS開發(fā) UIWebView

2009-06-15 15:16:00

netbeans sw平臺(tái)開發(fā)

2011-07-28 10:11:54

iPhone開發(fā) 備忘

2011-02-28 13:04:27

RelativeLayAndroid Wid

2011-09-09 20:14:58

Android Wid

2011-09-07 17:54:40

Android Wid開發(fā)

2013-02-20 15:29:00

JSONAndroid開發(fā)

2010-07-13 09:02:19

Widget開發(fā)

2013-05-20 17:33:44

Android游戲開發(fā)自定義View

2013-05-20 17:13:17

Android游戲開發(fā)CanvasPaint

2009-07-09 17:33:39

2009-08-31 09:41:05

C#反射靜態(tài)方法開發(fā)

2011-08-22 13:46:15

iPhone開發(fā)GameKit 藍(lán)牙

2009-09-07 06:18:57

C#窗體設(shè)計(jì)器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 一区二区三区四区不卡视频 | 精品一区二区三区免费视频 | 97精品视频在线观看 | 久久999 | 精品久久国产 | 中文字幕亚洲国产 | 最近免费日本视频在线 | 在线色网 | 免费一区 | 精品视频一区二区三区 | 亚洲草草视频 | 伊人激情综合网 | 亚洲精品欧美精品 | 欧美一区二区在线播放 | 久久久av| 亚洲精品乱码久久久久久按摩观 | 一区观看| 欧美videosex性极品hd | 国产精品久久久久久久久动漫 | 久久久99精品免费观看 | 久久久国产一区二区 | 国产电影一区二区三区爱妃记 | www.一区二区三区.com | 亚洲色图综合 | 国产区免费视频 | 亚洲国产精品久久久久久 | 一区二区三区免费 | 精品免费国产一区二区三区四区介绍 | 亚洲日本中文字幕在线 | 欧美日韩综合 | 亚洲精选一区 | 91精品国产综合久久久久久丝袜 | 亚洲精品成人免费 | 伊人伊人 | 91精品国产乱码久久久久久久久 | 欧美日韩成人在线观看 | 第四色影音先锋 | 欧美亚洲国语精品一区二区 | 国产乱人伦精品一区二区 | 青青久久 | 91av精品|