標籤:
在安卓中,有不止一種方法從你的應用截取使用者互動事件。在你的使用者介面中考慮事件,途徑就是從使用者介面中的一個指定的view對象中捕獲事件。該view提供了這樣做的方法。
在你用來組成你布局的不同的view類中,你或許注意到了一些公用的回調方法似乎看起來對UI事件有用。這些方法由安卓的架構調用,當各自的操作在對象中發生時。例如,當一個view (一個按鈕)被觸摸,在這個對象中的onTouchEvent() 方法就會被調用。然而,為了攔截這個事件,你必須繼承該類(button )並且重寫該方法(onTouchEvent)。然而,為了處理這樣的一個事件而繼承每一個view對象或許不實際。這就是為什麼View 類經常包含一組嵌套的調用介面讓你可以跟方便的定義(事件處理方法)。這些介面,叫做事件監聽者( event listeners),用來捕獲使用者與UI的互動。當你更加平常的為你的使用者互動使用事件監聽者,當你想繼承一個view類,為了建立一個自訂群組件,或許可以使用一次。或許你想要繼承Button類來讓一些東西更加精美。在這樣的情況下,你或許需要為你的類定義一個預設事件行為,使用該類的事件處理者(event handlers.). 事件監聽者(Event Listeners)一個事件監聽者是在view類中的一個介面,它包含了一個簡單的回呼函數。這些方法將會被安卓架構調用,當該view的監聽者已經被註冊並且通過使用者ui 項被觸發。包含了事件監聽者介面的都有如下回調方法:
onClick()
來自View.OnClickListener.。當使用者觸摸該item(觸摸模式下),或者使用導航鍵或軌跡球使焦點聚集在該項上並且按下了適當的"enter"(進入)按鍵或者在軌跡球上執行了按下操作。
onLongClick()來自
View.OnLongClickListener.。當使用者持續觸摸item時(觸摸模式下),或者使用導航鍵或軌跡球使焦點聚集在該項上並且持續按著適當的"enter"(進入)按鍵或者在軌跡球上執行持續按下操作(持續一秒)。
onFocusChange()來自
View.OnFocusChangeListener 當使用者使用導航鍵或者軌跡球導航到或者離開該item 時。
onKey()
來自View.OnKeyListener. 當使用者聚焦在了項目上並且按下或鬆開裝置上的按鍵時
onTouch()
來自View.OnTouchListener.當使用者執行一個合格的觸摸操作,包括按下,釋放或者任何螢幕上的手勢動作(在項目的邊界內)
onCreateContextMenu()
來自View.OnCreateContextMenuListener. 當操作功能表開始構建時調用(如持續“長按”的結果)。查看在 Menus開發嚮導中關於操作功能表的討論。這些方法是它們各自介面的唯一方法。為定義其中的一個方法並且處理你的事件,在你的activity中實現嵌套的介面,或者作為一個匿名類定義它。然後,傳遞一個你的執行個體引用給各自的View.set...Listener()方法。 method (例如,調用setOnClickListener()並且傳遞一個你執行個體化的OnClickListener)下面一個案例展示了如何為一個按鈕註冊一個on-click監聽者。
// 為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,如果你沒有處理它或者該事件應該繼續傳遞給其它on-click監聽者。
onKey() - 該方法返回一個布爾類型來表明你是否消耗了該事件並且不應該進一步傳遞下去。也就是說,返回true表明你處理了該事件並且它應該在這停下來;返回false,如果你沒有處理它或者該事件應該繼續傳遞給其它on-click監聽者。
onTouch() - 該方法返回一個布爾類型來表明你是否消耗了該事件。重要的是該事件可以有多個符合觸發條件的操作。因此,當按下事件被接受到,如果你返回了false,表明你沒有處理該事件並且對這個事件的後續行動不感興趣。因此,你不會為每一個操作都調用該事件,如手勢動作,或者最後的抬手動作(up action event)。
請記住,硬體按鈕事件總是傳遞給當前焦點視圖。從view的頂層開始向下分發,直到到達適當的地方。如果你的view(或者在view中的子view)獲得了焦點,之後你可以通過dispatchKeyEvent()方法查看到事件的移動。作為一個備選方法來從你的view中捕獲按鍵事件,你還可以在你activity中的
onKeyDown() 和
onKeyUp().內收到各種事件。並且,當你的應用輸入文本時,需要注意的是許多裝置只有軟體的輸入方法。這些方法不需要按鍵支援,或使用聲音輸入,手寫,等等。即使一個輸入方法呈現了一個類似鍵盤的介面,它通常也不會觸發onKeyDown()這類的事件。你永遠不應該建立UI來約束指定按鍵的按壓,除非你想要限制你應用使用裝置的硬體盤。特別的,當使用者按下返回按鈕時,不要依賴於這些方法來確認輸入;改為使用像IME_ACTION_DONE一樣的操作來表明該輸入方法並且讓你的應用程式做出怎樣的反應。這可能會以一種有意義的方式來改變它的UI。避免設想一個軟體輸入方法應該是如何工作的,並且只需要信任它來為你的應用支援已經格式化的文本。
注意:安卓將會首先呼叫事件處理者,之後調用類中定義的適當的預設處理者。同樣的,從這些事件監聽者中返回true將會停止事件傳播給其它事件監聽者,並且阻塞view中的預設事件處理的回調。因此,當你返回true時,確定你想要終止該事件。 事件處理者(Event Handlers)如果你想自訂一個view組件,那麼你可能會定義一些回調方法作為預設的事件處理者來使用。在Custom Components, 這篇文章中,你將會看到一些被用作事件處理的公用回呼函數,包括:
onKeyDown(int, KeyEvent) - 當一個新的按鍵事件發生時調用
onKeyUp(int, KeyEvent) - 當一個按鍵鬆開(key up )事件發生時調用
onTrackballEvent(MotionEvent) - 當一個軌跡球運動事件發生時
onTouchEvent(MotionEvent) - 當一個螢幕觸摸事件發生時
onFocusChanged(boolean, int, Rect) - 當該view獲得或失去焦點時
這還有其他的一些你需要注意的方法,它們不是view類的一部分,但是可以直接影響你能處理事件的方式。因此,當在你的布局中管理更多複合事件時,考慮這些方法:
Activity.dispatchTouchEvent(MotionEvent) -允許你的activity攔截所有的觸摸事件,在他們分發給window之前。
ViewGroup.onInterceptTouchEvent(MotionEvent) - 允許一個viewgroup 來觀察事件是否派遣給了子view。
ViewParent.requestDisallowInterceptTouchEvent(boolean) -調用該方法取決於父視圖,表明它不應該通過onInterceptTouchEvent(MotionEvent).攔截觸摸事件。
觸摸模式(Touch Mode)當使用者使用方向鍵或軌跡球在使用者介面上移動時,給予活動項(如按鈕)焦點是必須的,這樣使用者可以看見什麼輸入將會被接受。如果該裝置有觸摸能力,並且使用者開始通過觸摸來與介面互動,那麼並不需要高亮顯示項目,或者給指定view 一個焦點。因此,有一個互動模式叫做“觸摸模式”(當今的安卓手機主要是該模式,因它沒有硬體輸入裝置)對於一個可觸摸的裝置,移動使用者觸摸了螢幕,裝置將會進入觸摸模式。從此刻開始,只有當view因為isFocusableInTouchMode()為true時才可被聚焦,如文本編輯組件。其它view都是可觸摸的,如按鈕,在觸摸時將不會獲得焦點;當按下時,他們僅僅的啟用他們的on-click 監聽者。任何時候,使用者點擊一個方向鍵或滑動軌跡球,裝置將會退出觸摸模式並且找到一個view使其獲得焦點。現在,使用者可以繼續與使用者介面互動,不使用觸控螢幕幕這種方式。觸摸模式狀態一直維持在整個系統中(所有Windows和activitys ).為查詢目前狀態,你可以調用
isInTouchMode() 來查看裝置當前是否處於觸摸模式。處理焦點(Handling Focus )架構將會處理常規響應使用者輸入時的的焦點移動。這包括當view移除或隱藏時改變焦點,或一個新的view變為可用。view通過isFocusable()方法來表明他們獲得焦點的意願。改變view是否能獲得焦點,調用setFocusable()。當處於觸摸模式,你或許需要通過isFocusableInTouchMode()查詢一個view是否允許聚焦。通過使用
setFocusableInTouchMode()你可以改變它。焦點的移動是基於一個演算法的,它順著一個給定的方向尋找最近的(view)。少數情況下,預設演算法或許不符合開發人員的要求。在這種情況下,你可以提供詳細的覆蓋,通過在布局檔案中使用如下xml 屬性:nextFocusDown,nextFocusLeft, nextFocusRight, 和 nextFocusUp。將其中的一個屬性添加到view上。該屬性的值是下一個需要擷取焦點的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設定一樣(反之亦然),focus 焦點將會上-下 下-上的迴圈移動。如果你想要在你UI中什麼一個view是可設定焦點(當它一般情況下不是時),為view添加
android:focusable xml屬性,在你的布局檔案中聲明。設定該值為true。你也可以聲明該view的可聚焦性,當在觸摸模式時通過
android:focusableInTouchMode.為請求一個特別的view獲得焦點,調用requestFocus()為監聽焦時間點事件(當一個view獲得或失去焦點時通知),使用onFocusChange(),在上文#事件監聽者(Event Listeners)中討論的。
安卓 Input Events(輸入事件)