View的Touch事件分析

本文深入剖析Android中触摸事件的传递流程,从DecorView开始,详细讲解Activity、PhoneWindow如何处理触屏事件。接着探讨View的Touch事件特性,包括View和ViewGroup如何分发和处理触摸事件,特别是onTouchEvent方法的角色。最后,分析了点击和长按事件的触发条件,以及ViewGroup中事件的拦截和分发机制。
摘要由CSDN通过智能技术生成


分析来自Android8.1.0源码

DecorView的Touch事件处理

我们现在先关注View相关的事件处理,先不关心如何到达View的。后面还会分析如何到达View。

我们先从DecorView的Touch事件处理开始

public class DecorView {
   
    private PhoneWindow mWindow;
	@Override
	public boolean dispatchTouchEvent(MotionEvent ev) {
   
   		final Window.Callback cb = mWindow.getCallback();
    	return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
            	? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
	}
}
  1. 获取PhoneWindow对象的Callback对象。PhoneWindow是在Activityattach方法中创建的,并且Activity实现了Window.Callback,并传递给PhoneWindow作为Callback的回调。
  2. 如果不cbnullcb没有被销毁,mFeatureId小于0就会执行Window.Callback对象的dispatchTouchEvent方法。Activity运行时,前两个满足,当创建Activity的时候mFeatureId实际为-1。所以会调用Window.Callback对象的dispatchTouchEvent方法,也就是Activity实现的方法。

Activity中的Touch事件处理函数

有touch事件来的时候,会调用Activity的dispatchTouchEvent()派发事件,然后会调用getWindow().superDispatchTouchEvent(ev)派发事件,最终会调用布局中的View.

public class Activity extends ContextThemeWrapper
        implements Window.Callback {
   
	public boolean dispatchTouchEvent(MotionEvent ev) {
   
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
   
            onUserInteraction();
        }
        if (getWindow().superDispatchTouchEvent(ev)) {
   
            return true;
        }
        return onTouchEvent(ev);
    }
}
  1. 如果是MotionEvent.ACTION_DOWN会调用onUserInteraction接口
  2. 获取Window对象,实际为PhoneWindow对象。并调用其superDispatchTouchEvent方法,如果处理了直接返回true
  3. 如果Window对象调用superDispatchTouchEvent没有处理事件,就直接调用ActivityonTouchEvent方法。

因为Window对象实际为PhoneWindow对象,我们继续分析一下PhoneWindowsuperDispatchTouchEvent方法。

PhoneWindow对象superDispatchTouchEvent

public class PhoneWindow extends Window {
   
	@Override
	public boolean superDispatchTouchEvent(MotionEvent event) {
   
    	return mDecor.superDispatchTouchEvent(event);
	}
}

将会调用DecorViewsuperDispatchTouchEvent

public class DecorView extends FrameLayout {
   
	public boolean superDispatchTouchEvent(MotionEvent event) {
   
    	return super.dispatchTouchEvent(event);
	}
}

最后会调用父类的dispatchTouchEvent方法

在这里插入图片描述

FrametLaout继承ViewGroupViewGroup继承自View,并复写了View的dispatchTouchEvent方法。

总结:ActivityTouch会调用到PhoneWindowsuperDispatchTouchEvent方法处理Touch事件,PhoneWindow又交由DecorViewsuperDispatchTouchEvent方法处理,DecorView会调用其父类的dispatchTouchEvent来处理,也就是ViewGroupdispatchTouchEvent来处理。

下面我们在分析ViewGroupdispatchTouchEvent之前我们先来分析一下ViewdispatchTouchEvent处理

View的Touch事件处理特性

  • View中的Touch事件一个是View控件的Touch事件处理,一个是ViewGroup控件的Touch事件处理,二者处理方式有所不同
  • ViewGroupTouch事件处理是先由子View控件处理,子View控件没有消耗,然后有父View控件进行处理.
  • 对于ViewGroup控件可以通过onInterceptTouchEvent的方法拦截Touch事件
  • View中的Touch事件处理会先调用dispatchTouchEvent分发,然后调用onTouch处理,未处理会调用onTouchEvent处理。View控件还是ViewGroup控件处理逻辑都是一致

View控件的Touch事件处理

View处理Touch事件时首先被调用的是dispatchTouchEvent(),此方法的主要工作是调用恰当的方法进行处理.

public class View{
   
	public boolean dispatchTouchEvent(MotionEvent event) {
   
        ......
        if (onFilterTouchEventForSecurity(event)) {
   
            if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
   
                result = true;
            }
            //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;
            }
        }
        ......
    }
}

先调用onFilterTouchEventForSecurity方法是否需要过滤事件,我们先来看一下此方法。

public class View {
   
    public boolean onFilterTouchEventForSecurity(MotionEvent event) {
   
        //noinspection RedundantIfStatement
        if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0
                && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) {
   
            // Window is obscured, drop this touch.
            return false;
        }
        return true;
    }
}

检查ViewWindow是否被遮盖,如果被遮盖就过滤掉事件。

接着我们继续分析dispatchTouchEvent方法。

public class View{
   
	public boolean dispatchTouchEvent(MotionEvent event) {
   
        ......
        if (onFilterTouchEventForSecurity(event)) {
   
            if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
   
                result = true;
            }
            ......
        }
        ......
    }
}

接着检查ENABLED_MASK,也就是View检查是否enable,因为只有enable的状态下的View才能处理事件。接着调用handleScrollBarDragging方法,也就是处理滑动scroll bar事件,如果是,resulttrue

我们继续分析。


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值