Android官方文件—User Interface(Input Events)
輸入事件
在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部分所述。