Android OnTouchEvent和OnClick、OnLongClick、OnTouch、TouchDelegate关系

6 篇文章 0 订阅
3 篇文章 0 订阅

说明:本博客为原创,转载请注明出处 http://blog.csdn.net/gucun4848
由于作者水平有限,错误在所难免,请见谅,可以留言,本人会及时改正


索引


基于上篇Android Touch事件总结一,本篇介绍Touch事件和Click、LongClick、Touch、TouchDelegate的关系。

OnClick

public void setOnClickListener(OnClickListener l){
//注册点击事件
}

用法很简单这里只介绍下View什么时候触发这个回调事件,源码如下:

public boolean onTouchEvent(MotionEvent event)
...
switch (action) {

    case MotionEvent.ACTION_UP:
    ... 
     // take focus if we don't have it already and we should in touch mode.
        boolean focusTaken = false;

        if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
            focusTaken = requestFocus();
        }

        if (prepressed) {
        // The button is being released before we actually
        // showed it as pressed.  Make it show the pressed
        // state now (before scheduling the click) to ensure the user sees it.
            setPressed(true, x, y);
        }

        if (!mHasPerformedLongPress && !mIgnoreNextUpEvent){
        // This is a tap, so remove the longpress check
        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();
            }
            //触发OnClick事件
            if (!post(mPerformClick)) {
                performClick();
            }
        }
        }
...
// 可以看到,在OnTouchEvent方法中,接收到ACTION_UP事件后,判断如果View当前不是FocusableInTouchMode状态,没有LongPressed状态,触发OnClick事件。

OnLongClick

public void setOnLongClickListener(OnLongClickListener l){
//注册长按事件
}

用法很简单这里只介绍下View什么时候触发这个回调事件,源码如下:

 public boolean onTouchEvent(MotionEvent event)
 ...
 //还是在OnTouchEvent方法,接收到DOWN事件后,通过PostDelayed()实现
 case MotionEvent.ACTION_DOWN:

    mHasPerformedLongPress = false;

    // Walk up the hierarchy to determine if we're inside a scrolling container.
    boolean isInScrollingContainer = isInScrollingContainer();

    // For views inside a scrolling container, delay the pressed feedback for
    // a short period in case this is a scroll.
    if (isInScrollingContainer) {
        mPrivateFlags |= PFLAG_PREPRESSED;
        if (mPendingCheckForTap == null) {
            mPendingCheckForTap = new CheckForTap();
        }
        mPendingCheckForTap.x = event.getX();
        mPendingCheckForTap.y = event.getY();
        // mPendingCheckForTap中触发事件
        postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
    } else {
        // Not inside a scrolling container, so show the feedback right away
        setPressed(true, x, y);
        // 触发事件
        checkForLongClick(0, x, y);
    }

    break;

OnTouchListener

public void setOnTouchListener(OnTouchListener l){
//注册触摸事件,这个回调会拦截View自身的OnTouchEvent方法。
}

用法很简单这里只介绍下View什么时候触发这个回调事件,源码如下:

public boolean dispatchTouchEvent(MotionEvent event) {
...
    if (onFilterTouchEventForSecurity(event)) {
        //noinspection SimplifiableIfStatement
        ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnTouchListener != null
                   && (mViewFlags & ENABLED_MASK) == ENABLED
                   && li.mOnTouchListener.onTouch(this, event)) {
            result = true;
        }

        if (!result && onTouchEvent(event)) {
            result = true;
        }
    }
}
// 在分发事件中先触发OnTouch回调,如果OnTouch回调中不消费事件,才会触发View自身的OnTouchEvent方法。

setTouchDelegate

public void setTouchDelegate(TouchDelegate l){
//注册触摸委派事件,这个回调常用于增加自身的可触摸面积。
//实例TouchDelegate对象需要两个参数Rect bounds, View delegateView
//bounds 触摸区域大小
//delegateView 委派事件的View
//这里需要**注意**的是需要delegateView的ParentView调用setTouchDelegate()方法!
}

这里看下View的源码:

public boolean onTouchEvent(MotionEvent event) {
        ...
        //在View的OnTouchEvent方法中,优先调用的委派事件       
        //这里需要注意的是委派事件的View的ParentView必须保证自身的onTouchEvnet方法会被调用!
        if (mTouchDelegate != null) {
            if (mTouchDelegate.onTouchEvent(event)) {
                return true;
            }
        }
        ...
}

//这里是TouchDelegate中的onTouchEvent方法
public boolean onTouchEvent(MotionEvent event) {
        int x = (int)event.getX();
        int y = (int)event.getY();
        boolean sendToDelegate = false;
        boolean hit = true;
        boolean handled = false;

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Rect bounds = mBounds;
            //这里判断当前的触摸位置是不是在委派的边界内
            if (bounds.contains(x, y)) {
                mDelegateTargeted = true;
                sendToDelegate = true;
            }
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_MOVE:
            sendToDelegate = mDelegateTargeted;
            if (sendToDelegate) {
                Rect slopBounds = mSlopBounds;
                if (!slopBounds.contains(x, y)) {
                    hit = false;
                }
            }
            break;
        case MotionEvent.ACTION_CANCEL:
            sendToDelegate = mDelegateTargeted;
            mDelegateTargeted = false;
            break;
        }
        //触摸位置在边界内
        if (sendToDelegate) {
            final View delegateView = mDelegateView;

            if (hit) {
                // Offset event coordinates to be inside the target view
                event.setLocation(delegateView.getWidth() / 2, delegateView.getHeight() / 2);
            } else {
                // Offset event coordinates to be outside the target view (in case it does
                // something like tracking pressed state)
                int slop = mSlop;
                event.setLocation(-(slop * 2), -(slop * 2));
            }
            //调用了委派事件的View的dispatchTouchEvent方法.
            handled = delegateView.dispatchTouchEvent(event);
        }
        return handled;
    }

Demo

GitHub地址: GitHub
环境: Windows7+JAVA8
IDE: AndroidStdio2.2.2
compileSdkVersion:24
测试设备:Nexus5(6.0.1)

运行Demo的时候需要在Manifest.xml中启动项设置成MainViewTouchClickActivity

点击灰色区域,可以触发黄色View的OnClick事件
TouchDelegateListener


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值