Android 中屏幕点击事件的实现 Android onTouchEvent, onClick及onLongClick的调用机制

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都囊括了,这仅仅是几个比較典型的样例,效果例如以下:

Android 中屏幕点击事件的实现
Android onTouchEvent, onClick及onLongClick的调用机制

Android 中屏幕点击事件的实现
Android onTouchEvent, onClick及onLongClick的调用机制

Android 中屏幕点击事件的实现
Android onTouchEvent, onClick及onLongClick的调用机制

Android 中屏幕点击事件的实现
Android onTouchEvent, onClick及onLongClick的调用机制

Android 中屏幕点击事件的实现
Android onTouchEvent, onClick及onLongClick的调用机制

Android 中屏幕点击事件的实现
Android onTouchEvent, onClick及onLongClick的调用机制

 

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);

    }

效果与上图类似,仅仅是文字不一样

Android 中屏幕点击事件的实现
Android onTouchEvent, onClick及onLongClick的调用机制

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   就是拖动的感觉

Android 中屏幕点击事件的实现
Android onTouchEvent, onClick及onLongClick的调用机制

6.        连续点击按键时发生的事件

Publicboolean onKeyMultiple(int keyCode,int repeatCount,KeyEvent event)

{

 Return super.onKeyMultiple(keyCode, repeatCount, event);

}



针对屏幕上的一个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()方法。