在android下,事件的發生是在監聽器下進行,android系統能夠響應按鍵事件和觸摸屏事件,事件說明例如以下:
onClick(View v)一個普通的點擊button事件
boolean onKeyMultiple(int keyCode,int repeatCount,KeyEvent event)用於在多個事件連續時發生,用於按鍵反復,必須重載@Override實現
boolean onKeyDown(int keyCode,KeyEvent event)用於在按鍵進行按下時發生
boolean onKeyUp(int keyCode,KeyEvent event)用於在按鍵進行釋放時發生
onTouchEvent(MotionEvent event)觸摸屏事件,當在觸摸屏上有動作時發生
boolean onKeyLongPress(int keyCode, KeyEvent event)當你長時間按時發生
對於這幾個函數的實例
首先我們建立一個android項目,當項目建立好之后,直接在默認的main.xml文件里拖放一個button按鈕,其它的不須要在這里做什么了,然后就能夠到命名好的.java文件里進行先關代碼的書寫;
1. 對要使用的控件進行引用,當然你也能夠用到的時候再在相關類控件加入引用
import android.app.Activity; import android.os.Bundle; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.widget.Button; import android.widget.Toast; |
2. 獲得相關對象,設置控件監聽器
Button button=(Button) findViewById(R.id.button1); //設置監聽 button.setOnClickListener(newButton.OnClickListener() { @Override publicvoid onClick(View v) { //TODO Auto-generated method stub DisplayToast("事件觸發成功"); } }); |
請注意這里末尾使用的是分號“;這里就是獲得button的實例,然后對他進行監聽,當用戶點擊時就會發生onClick事件,這里還用到一個方法,就是顯示一個短消息,在屏幕停留幾秒鍾就會自己主動消失,其方法例如以下:
publicvoid DisplayToast(String str) { Toast.makeText(this, str, Toast.LENGTH_SHORT).show(); } |
當然你也能夠設置顯示長點,即Toast.LENGTH_SHORT改為Toast.LENGTH_LONG
3. 當按鍵按下是發生的事件
public boolean onKeyDown(int keyCode,KeyEvent event) { switch(keyCode) { case KeyEvent.KEYCODE_0: DisplayToast("你按下數字鍵0"); break; case KeyEvent.KEYCODE_DPAD_CENTER: DisplayToast("你按下中間鍵"); break;sss case KeyEvent.KEYCODE_DPAD_DOWN: DisplayToast("你按下下方向鍵"); break; case KeyEvent.KEYCODE_DPAD_LEFT: DisplayToast("你按下左方向鍵"); break; case KeyEvent.KEYCODE_DPAD_RIGHT: DisplayToast("你按下右方向鍵"); break; case KeyEvent.KEYCODE_DPAD_UP: DisplayToast("你按下上方向鍵"); break; case KeyEvent.KEYCODE_ALT_LEFT: DisplayToast("你按下組合鍵alt+←"); break; } return super.onKeyDown(keyCode, event); } |
這里全部的keyCode都囊括了,這僅僅是幾個比較典型的樣例,效果例如以下:
|
|
|
|
|
|
4. 當按鍵彈起時發生的事件,代碼例如以下:
publicboolean onKeyUp(int keyCode,KeyEvent event) { switch(keyCode) { case KeyEvent.KEYCODE_0: DisplayToast("松開數字鍵0"); break; case KeyEvent.KEYCODE_DPAD_CENTER: DisplayToast("松開中間鍵"); break; case KeyEvent.KEYCODE_DPAD_DOWN: DisplayToast("松開下方向鍵"); break; case KeyEvent.KEYCODE_DPAD_LEFT: DisplayToast("松開左方向鍵"); break; case KeyEvent.KEYCODE_DPAD_RIGHT: DisplayToast("松開右方向鍵"); break; case KeyEvent.KEYCODE_DPAD_UP: DisplayToast("松開上方向鍵"); break; case KeyEvent.KEYCODE_ALT_LEFT: DisplayToast("松開組合鍵alt+←"); break; } returnsuper.onKeyUp(keyCode, event); } |
效果與上圖類似,僅僅是文字不一樣
5. 觸摸屏事件,當用手或者用筆在觸摸屏上做動作是發生,相關代碼例如以下:
public boolean onTouchEvent(MotionEvent event) { int Action = event.getAction(); float X = event.getX(); float Y = event.getY(); mAction.setText("Action = " + Action); mPosition.setText("Position = (" + X + " , " + Y + ")"); return true; } 當中 Action變量會得到三個返回值,代表三種不同的觸摸階段 Action = 0 : ACTION_DOWN Action = 1 : ACTION_UP Action = 2 ; ACTION_MOVE 就是拖動的感覺 |
6. 連續點擊按鍵時發生的事件
Publicboolean onKeyMultiple(int keyCode,int repeatCount,KeyEvent event)
{
Return super.onKeyMultiple(keyCode, repeatCount, event);
}
Android onTouchEvent, onClick及onLongClick的調用機制
針對屏幕上的一個View控件,Android怎樣區分應當觸發onTouchEvent,還是onClick,亦或是onLongClick事件?
在Android中,一次用戶操作能夠被不同的View按次序分別處理,並將全然響應了用戶一次UI操作稱之為消費了該事件(consume),那么Android是按什么次序將事件傳遞的呢?又在什么情況下判定為消費了該事件?
搞清楚這些問題對於編寫出能正確響應UI操作的代碼是非常重要的,尤其當屏幕上的不同View須要針對此次UI操作做出各種不同響應的時候更是如此,一個典型樣例就是用戶在桌面上放置了一個Widget,那么當用戶針對widget做各種操作時,桌面本身有的時候要對用戶的操作做出響應,有時忽略。僅僅有搞清楚事件觸發和傳遞的機制才有可能保證在界面布局非常復雜的情況下,UI控件仍然能正確響應用戶操作。
1. onTouchEvent
onTouchEvent中要處理的最經常使用的3個事件就是:ACTION_DOWN、ACTION_MOVE、ACTION_UP。
這三個事件標識出了最主要的用戶觸摸屏幕的操作,含義也非常清楚。盡管大家天天都在用它們,可是有一點請留意,ACTION_DOWN事件作為起始事件,它的重要性是要超過ACTION_MOVE和ACTION_UP的,假設發生了ACTION_MOVE或者ACTION_UP,那么一定以前發生了ACTION_DOWN。
從Android的源碼中能看到基於這樣的不同重要性的理解而實現的一些交互機制,SDK中也有明白的提及,比如在ViewGroup的onInterceptTouchEvent方法中,假設在ACTION_DOWN事件中返回了true,那么興許的事件將直接發給onTouchEvent,而不是繼續發給onInterceptTouchEvent。
2. onClick、onLongClick與onTouchEvent
以前看過一篇帖子提到,假設在View中處理了onTouchEvent,那么就不用再處理onClick了,由於Android僅僅會觸發當中一個方法。這個理解是不太正確的,針對某個view,用戶完畢了一次觸碰操作,顯然從傳感器上得到的信號是手指按下和抬起兩個操作,我們能夠理解為一次Click,也能夠理解為發生了一次ACTION_DOWN和ACTION_UP,那么Android是怎樣理解和處理的呢?
在Android中,onClick、onLongClick的觸發是和ACTION_DOWN及ACTION_UP相關的,在時序上,假設我們在一個View中同一時候覆寫了onClick、onLongClick及onTouchEvent的話,onTouchEvent是最先捕捉到ACTION_DOWN和ACTION_UP事件的,其次才可能觸發onClick或者onLongClick。基本的邏輯在View.java中的onTouchEvent方法中實現的:
case MotionEvent.ACTION_DOWN:
mPrivateFlags |= PRESSED;
refreshDrawableState();
if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) {
postCheckForLongClick();
break;
case MotionEvent.ACTION_UP:
if ((mPrivateFlags & PRESSED) != 0) {
boolean focusTaken = false;
if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
focusTaken = requestFocus();
if (!mHasPerformedLongPress) {
if (mPendingCheckForLongPress != null) {
removeCallbacks(mPendingCheckForLongPress);
if (!focusTaken) {
performClick();
break;
能夠看到,Click的觸發是在系統捕捉到ACTION_UP后發生並由performClick()運行的,performClick里會調用先前注冊的監聽器的onClick()方法:
public boolean performClick() {
if (mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
mOnClickListener.onClick(this);
return true;
return false;
LongClick的觸發則是從ACTION_DOWN開始,由postCheckForLongClick()方法完畢:
private void postCheckForLongClick() {
mHasPerformedLongPress = false;
if (mPendingCheckForLongPress == null) {
mPendingCheckForLongPress = new CheckForLongPress();
mPendingCheckForLongPress.rememberWindowAttachCount();
postDelayed(mPendingCheckForLongPress, ViewConfiguration.getLongPressTimeout());
能夠看到,在ACTION_DOWN事件被捕捉后,系統會開始觸發一個postDelayed操作,delay的時間在Eclair2.1上為500ms,500ms后會觸發CheckForLongPress線程的運行:
class CheckForLongPress implements Runnable {
public void run() {
if (isPressed() && (mParent != null)
&& mOriginalWindowAttachCount == mWindowAttachCount) {
if (performLongClick()) {
mHasPerformedLongPress = true;
假設各種條件都滿足,那么在CheckForLongPress中運行performLongClick(),在這種方法中將調用onLongClick():
public boolean performLongClick() {
if (mOnLongClickListener != null) {
handled = mOnLongClickListener.onLongClick(View.this);
從實現中能夠看到onClick()和onLongClick()方法是由ACTION_DOWN和ACTION_UP事件捕捉后依據各種情況終於確定是否觸發的,也就是說假設我們在一個Activity或者View中同一時候監聽或者覆寫了onClick(),onLongClick()和onTouchEvent()方法,並不意味着僅僅會發生當中一種。
以下是一個onClick被觸發的基本時序的Log:
04-05 05:57:47.123: DEBUG/TSActivity(209): onTouch ACTION_DOWN
04-05 05:57:47.263: DEBUG/TSActivity(209): onTouch ACTION_UP
04-05 05:57:47.323: DEBUG/TSActivity(209): onClick
能夠看出是按ACTION_DOWN -> ACTION_UP -> onClick的次序發生的。
以下是一個onLongClick被觸發的基本時序的Log:
04-05 06:00:04.133: DEBUG/TSActivity(248): onTouch ACTION_DOWN
04-05 06:00:04.642: DEBUG/TSActivity(248): onLongClick
04-05 06:00:05.083: DEBUG/TSActivity(248): onTouch ACTION_UP
能夠看到,在保持按下的狀態一定時間后會觸發onLongClick,之后抬起手才會發生ACTION_UP。
3. onClick和onLongClick能同一時候發生嗎?
要弄清楚這個問題僅僅要理解Android對事件處理的所謂消費(consume)概念就可以,一個用戶的操作會被傳遞到不同的View控件和同一個控件的不同監聽方法處理,不論什么一個接收並處理了該次事件的方法假設在處理完后返回了true,那么該次event就算被全然處理了,其它的View或者監聽方法就不會再有機會處理該event了。
onLongClick的發生是由單獨的線程完畢的,而且在ACTION_UP之前,而onClick的發生是在ACTION_UP后,因此同一次用戶touch操作就有可能既發生onLongClick又發生onClick。這樣是不是不可思議?所以及時向系統表示“我已經全然處理(消費)了用戶的此次操作”,是非常重要的事情。比如,我們假設在onLongClick()方法的最后return true,那么onClick事件就沒有機會被觸發了。
以下的Log是在onLongClick()方法return false的情況下,一次觸碰操作的基本時序:
04-05 06:00:53.023: DEBUG/TSActivity(277): onTouch ACTION_DOWN
04-05 06:00:53.533: DEBUG/TSActivity(277): onLongClick
04-05 06:00:55.603: DEBUG/TSActivity(277): onTouch ACTION_UP
04-05 06:00:55.663: DEBUG/TSActivity(277): onClick
能夠看到,在ACTION_UP后仍然觸發了onClick()方法。