Android系统中长按事件的实现机制解析

Android的触摸消息中,已经实现了三种监测,它们分别是

1)pre-pressed:对应的语义是用户轻触(tap)了屏幕

2)pressed:对应的语义是用户点击(press)了屏幕

3)long pressed:对应的语义是用户长按(long press)了屏幕

下图是触摸消息随时间变化的时间轴示意图:

Android系统中长按事件的实现机制解析


其中,t0和t1定义在ViewConfiguration类中,标识了tap和longpress的超时时间,定义如下:

/**   * Defines the duration in milliseconds we will wait to see if a touch event    * is a tap or a scroll. If the user does not move within this interval, it is   * considered to be a tap.    */   private static final int TAP_TIMEOUT = 115// t0       /**   * Defines the duration in milliseconds before a press turns into   * a long press   */   private static final int LONG_PRESS_TIMEOUT = 500// t1  

代码中实现监测的地方在View类的OnTouchEvent函数中,当View监测到ACTION_DOWN事件时,首先发送一个延迟为t0的异步消息,代码如下:

case MotionEvent.ACTION_DOWN:       if (mPendingCheckForTap == null) {           mPendingCheckForTap = new CheckForTap();       }       mPrivateFlags |= PREPRESSED;       mHasPerformedLongPress = false;       postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());       break;  

如果在t0时间内用户释放了屏幕,即ACTION_UP事件在t0时间内发生,则本次触摸对应的是pre-pressed处理代码,语义是"用户轻触(TAP)了一下屏幕";如果用户在t1时间内释放了屏幕,那么本次操作是一个"press"操作;如果用户超过t1时间释放屏幕,则系统认为监测到了长按事件。其中处理"press"操作的代码在类CheckForTap类中,处理长按操作的代码在类CheckForLongPress类中。而处理pre-pressed的代码在ACTION_UP事件响应中,ACTION_UP事件响应中大部分代码用于处理触摸的状态变化,如下所示:

case MotionEvent.ACTION_UP:       boolean prepressed = (mPrivateFlags & PREPRESSED) != 0//获取prepressed状态        if ((mPrivateFlags & PRESSED) != 0 || prepressed) { //如果是pressed状态或者是prepressed状态,才进行处理            // 如果当前view不具有焦点,则需要先获取焦点,因为我们当前处理触摸模式            boolean focusTaken = false;           if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {               focusTaken = requestFocus(); // 请求获得焦点            }              if (!mHasPerformedLongPress) { // 是否处理过长按操作了,如果是,则直接返回                // 进入该代码段,说明这是一个tap操作,首先移除长按回调操作                removeLongPressCallback();                   // Only perform take click actions if we were in the pressed state                if (!focusTaken) {                   // Use a Runnable and post this rather than calling                    // performClick directly. This lets other visual state                    // of the view update before click actions start.                    if (mPerformClick == null) {                       mPerformClick = new PerformClick();                   }                   if (!post(mPerformClick)) {                       performClick(); // 执行点击的处理函数                    }               }           }              if (mUnsetPressedState == null) {               mUnsetPressedState = new UnsetPressedState();           }              if (prepressed) {               mPrivateFlags |= PRESSED;               refreshDrawableState();               // 发送重置触摸状态的异步延迟消息                postDelayed(mUnsetPressedState,                       ViewConfiguration.getPressedStateDuration());           } else if (!post(mUnsetPressedState)) {               // If the post failed, unpress right now                mUnsetPressedState.run();           }           removeTapCallback(); // 移除tap的回调操作        }       break;  

在上面的代码分析中,可以看出,整个监测过程涉及到两个Runnable对象和一个利用Handler发送异步延迟消息的函数,下面就来分析一下:

1)PostDelayed函数

该函数的主要工作是获取UI线程的Handler对象,然后调用Handler类的postDelayed函数将指定的Runnable对象放到消息队列中。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/9df479337d8185755c79c70b341bcc1e.html