輸入事件
在Android上,有多種方法可以攔截用戶與您的應用程序交互的事件。在考慮用戶界面中的事件時,方法是從用戶與之交互的特定View對象中捕獲事件。 View類提供了這樣做的方法。
在用於構成佈局的各種View類中,您可能會注意到幾種對UI事件有用的公共回調方法。當在該對象上發生相應的操作時,Android框架會調用這些方法。例如,當觸摸View(例如Button)時,將在該對象上調用onTouchEvent()方法。但是,爲了攔截它,您必須擴展類並重寫該方法。但是,爲了處理這樣的事件而擴展每個View對象是不切實際的。這就是爲什麼View類還包含一組嵌套接口,其中包含可以更容易定義的回調。這些稱爲事件偵聽器的接口是捕獲用戶與UI交互的門票。
雖然您將更常使用事件偵聽器來偵聽用戶交互,但是有時您可能希望擴展View類,以構建自定義組件。也許你想擴展Button類以使某些東西更加花哨。在這種情況下,您將能夠使用類事件處理程序爲您的類定義默認事件行爲。
事件監聽器
事件偵聽器是View類中的一個接口,它包含一個回調方法。當用戶與UI中的項目交互觸發了已註冊偵聽器的View時,Android框架將調用這些方法。
事件偵聽器接口中包含以下回調方法:
onClick()
從View.OnClickListener。當用戶觸摸項目時(當處於觸摸模式時)或者使用導航鍵或軌跡球聚焦在項目上並按下合適的“輸入”鍵或按下軌跡球時調用此方法。
onLongClick()
從View.OnLongClickListener。當用戶觸摸並保持項目時(當處於觸摸模式時)或者使用導航鍵或軌跡球聚焦於項目並按下並按住合適的“輸入”鍵或按下並按住軌跡球時(一秒鐘)。
onFocusChange()
從View.OnFocusChangeListener。當用戶使用導航鍵或軌跡球導航到項目或遠離項目時,會調用此方法。
onKey()
來自View.OnKeyListener。當用戶專注於該項目並按下或釋放設備上的硬件密鑰時,將調用此方法。
onTouch()
從View.OnTouchListener。當用戶執行限定爲觸摸事件的動作時調用此方法,包括按下,釋放或屏幕上的任何移動手勢(在項目的範圍內)。
onCreateContextMenu()
從View.OnCreateContextMenuListener。這是在構建上下文菜單時調用的(由於持續的“長按”)。請參閱菜單開發人員指南中有關上下文菜單的討論。
這些方法是其各自界面的唯一居民。要定義其中一個方法並處理事件,請在Activity中實現嵌套接口或將其定義爲匿名類。然後,將實現的實例傳遞給相應的View.set ... Listener()方法。 (例如,調用setOnClickListener()並將其傳遞給OnClickListener。)
下面的示例顯示瞭如何爲Button註冊一個on-click監聽器。
// Create an anonymous implementation of OnClickListener
private OnClickListener mCorkyListener = new OnClickListener() {
public void onClick(View v) {
// do something when the button is clicked
}
};
protected void onCreate(Bundle savedValues) {
...
// Capture our button from layout
Button button = (Button)findViewById(R.id.corky);
// Register the onClick listener with the implementation above
button.setOnClickListener(mCorkyListener);
...
}
您可能還發現將OnClickListener實現爲Activity的一部分更方便。這將避免額外的類加載和對象分配。例如:
public class ExampleActivity extends Activity implements OnClickListener {
protected void onCreate(Bundle savedValues) {
...
Button button = (Button)findViewById(R.id.corky);
button.setOnClickListener(this);
}
// Implement the OnClickListener callback
public void onClick(View v) {
// do something when the button is clicked
}
...
}
請注意,上例中的onClick()回調沒有返回值,但是其他一些事件偵聽器方法必須返回一個布爾值。原因取決於事件。對於少數人來說,這就是原因:
- onLongClick() - 返回一個布爾值,表示您是否已經消耗了該事件,並且不應該進一步攜帶它。也就是說,返回true表示你已經處理了這個事件,它應該在這裏停止;如果您尚未處理它並且/或該事件應繼續到任何其他點擊監聽器,則返回false。
- onKey() - 返回一個布爾值,表示您是否已經消耗了該事件,並且不應該進一步攜帶它。也就是說,返回true表示你已經處理了這個事件,它應該在這裏停止;如果您尚未處理它並且/或該事件應繼續到任何其他on-key偵聽器,則返回false。
- onTouch() - 返回一個布爾值,指示您的偵聽器是否使用此事件。重要的是,此事件可以有多個相互跟隨的操作。因此,如果在收到向下操作事件時返回false,則表示您尚未使用該事件,並且對此事件的後續操作也不感興趣。因此,您不會在事件中調用任何其他操作,例如手指手勢或最終的上行動作事件。
請記住,硬件鍵事件始終傳遞到當前焦點的視圖。它們從View層次結構的頂部開始,然後向下調度,直到它們到達適當的目標。如果您的View(或您的View的子級)當前具有焦點,那麼您可以通過dispatchKeyEvent()方法查看事件。作爲通過View捕獲關鍵事件的替代方法,您還可以使用onKeyDown()和onKeyUp()接收Activity內的所有事件。
此外,在考慮應用程序的文本輸入時,請記住許多設備只有軟件輸入方法。這些方法不需要是基於密鑰的;有些人可能會使用語音輸入,手寫等。即使輸入方法呈現類似鍵盤的界面,它通常也不會觸發onKeyDown()系列事件。除非要將應用程序限制爲具有硬件鍵盤的設備,否則不應構建需要控制特定按鍵的UI。特別是,當用戶按下返回鍵時,不要依賴這些方法來驗證輸入;相反,使用IME_ACTION_DONE之類的操作來向輸入方法發出應用程序期望的反應信號,因此它可能會以有意義的方式更改其UI。避免假設軟件輸入方法應該如何工作,只要相信它就可以爲應用程序提供已經格式化的文本。
注意:Android將首先調用事件處理程序,然後調用類定義中的相應默認處理程序。因此,從這些事件偵聽器返回true將停止將事件傳播到其他事件偵聽器,並且還將阻止對View中的默認事件處理程序的回調。因此,請確保在返回true時終止事件。
事件處理程序
如果您正在從View構建自定義組件,那麼您將能夠定義幾個用作默認事件處理程序的回調方法。在有關自定義組件的文檔中,您將瞭解到一些用於事件處理的常見回調,包括:
- onKeyDown(int,KeyEvent) - 在發生新的鍵事件時調用。
- onKeyUp(int,KeyEvent) - 發生密鑰啓動事件時調用。
- onTrackballEvent(MotionEvent) - 在軌跡球運動事件發生時調用。
- onTouchEvent(MotionEvent) - 發生觸摸屏動作事件時調用。
- onFocusChanged(boolean,int,Rect) - 在視圖獲得或失去焦點時調用。
您應該注意一些其他方法,這些方法不是View類的一部分,但可以直接影響您處理事件的方式。因此,在佈局中管理更復雜的事件時,請考慮以下其他方法:
- Activity.dispatchTouchEvent(MotionEvent) - 這允許您的Activity在調度到窗口之前攔截所有觸摸事件。
- ViewGroup.onInterceptTouchEvent(MotionEvent) - 這允許ViewGroup在將事件分派給子視圖時觀察事件。
- ViewParent.requestDisallowInterceptTouchEvent(boolean) - 在父視圖上調用此方法以指示它不應使用onInterceptTouchEvent(MotionEvent)攔截觸摸事件。
觸摸模式
當用戶使用方向鍵或軌跡球導航用戶界面時,必須將焦點放在可操作的項目(如按鈕)上,以便用戶可以看到接受輸入的內容。但是,如果設備具有觸摸功能,並且用戶通過觸摸它開始與界面交互,則不再需要突出顯示項目或將焦點放在特定視圖上。因此,存在稱爲“觸摸模式”的交互模式。
對於具有觸控功能的設備,一旦用戶觸摸屏幕,設備將進入觸摸模式。從這一點開始,只有isFocusableInTouchMode()爲true的視圖纔是可聚焦的,例如文本編輯小部件。其他可觸摸的視圖,如按鈕,在觸摸時不會聚焦;他們只需在按下時觸發他們的點擊式聽衆。
每當用戶點擊方向鍵或使用軌跡球滾動時,設備將退出觸摸模式,並找到要獲得焦點的視圖。現在,用戶可以在不觸摸屏幕的情況下恢復與用戶界面的交互。
整個系統(所有窗口和活動)都保持觸摸模式狀態。要查詢當前狀態,可以調用isInTouchMode()來查看設備當前是否處於觸摸模式。
處理焦點
該框架將處理針對用戶輸入的例行焦點移動。這包括在刪除或隱藏視圖或新視圖可用時更改焦點。視圖表明他們願意通過isFocusable()方法獲得焦點。要更改View是否可以獲得焦點,請調用setFocusable()。在觸摸模式下,您可以查詢View是否允許使用isFocusableInTouchMode()進行焦點。您可以使用setFocusableInTouchMode()更改此設置。
焦點移動基於在給定方向上找到最近鄰居的算法。在極少數情況下,默認算法可能與開發人員的預期行爲不匹配。在這些情況下,您可以在佈局文件中提供以下XML屬性的顯式覆蓋:nextFocusDown,nextFocusLeft,nextFocusRight和nextFocusUp。將其中一個屬性添加到焦點所在的視圖中。將屬性的值定義爲應該給予焦點的View的id。例如:
<LinearLayout
android:orientation="vertical"
... >
<Button android:id="@+id/top"
android:nextFocusUp="@+id/bottom"
... />
<Button android:id="@+id/bottom"
android:nextFocusDown="@+id/top"
... />
</LinearLayout>
通常,在這種垂直佈局中,從第一個按鈕向上導航不會去任何地方,也不會從第二個按鈕向下導航。現在頂部按鈕已將底部按鈕定義爲nextFocusUp(反之亦然),導航焦點將從上到下和從下到上循環。
如果您想在UI中聲明View是可聚焦的(傳統上不是這樣),請在佈局聲明中將android:focusable XML屬性添加到View中。將值設置爲true。您還可以在觸摸模式下使用android:focusableInTouchMode將View聲明爲可聚焦。
要請求特定視圖獲得焦點,請調用requestFocus()。
要偵聽焦點事件(在View接收或失去焦點時收到通知),請使用onFocusChange(),如上面的Event Listeners部分所述。