View,ViewGroup的Touch事件的分发机制



移动信息安全的漏洞和逆向原理      【观点】世界上最好的语言是什么      58到家周俊鹏:webpack PK fis,我更喜欢前者
 

Andriod 从源码的角度详解View,ViewGroup的Touch事件的分发机制

标签: AndroidViewviewGroupdispatchTouchEventonTouchEvent
  45976人阅读  评论(69)  收藏  举报
  分类:
Android 基础教程(19) 

转载请注明本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/21696315),请尊重他人的辛勤劳动成果,谢谢!

今天这篇文章主要分析的是Android的事件分发机制,采用例子加源码的方式让大家深刻的理解Android事件分发的具体情况,虽然网上很多Android的事件分发的文章,有些还写的不错,但是我还是决定写这篇文章,用我自己的思维方式来帮助大家理解Android事件分发,Android事件分发到底有多重要呢?相信很多Android开发者都明白吧,这个我就不介绍了,我也写了很多篇文章里面涉及到Android的事件处理的问题,可能不理解Android事件分发的朋友会有点难理解吧,不过没关系,相信看了这篇文章的你会对Android事件分发有进一步的理解。我这篇文章分析的源码是Android 2.2的源码, 也许你会说,干嘛不去分析最新的源码呢?我这里要解释一下,Android 2.2的源码跟最新的源码在功能效果方面是一样的,只不过最新的源码相对于Android 2.2来说更加健壮一些, Android 2.2的事件处理的代码几乎都写在一个方法体里面,而最新的源码分了很多个方法写,如果用最新的源码调用方法会绕来绕去的,相信你看的也会晕,出于这个考虑,我就拿Android 2.2的源码来给大家分析。


ViewGroup的事件分发机制

我们用手指去触摸Android手机屏幕,就会产生一个触摸事件,但是这个触摸事件在底层是怎么分发的呢?这个我还真不知道,这里涉及到操作硬件(手机屏幕)方面的知识,也就是Linux内核方面的知识,我也没有了解过这方面的东西,所以我们可能就往上层来分析分析,我们知道Android中负责与用户交互,与用户操作紧密相关的四大组件之一是Activity, 所以我们有理由相信Activity中存在分发事件的方法,这个方法就是dispatchTouchEvent(),我们先看其源码吧

[java]  view plain  copy
 
  1. public boolean dispatchTouchEvent(MotionEvent ev) {  
  2.   
  3.         //如果是按下状态就调用onUserInteraction()方法,onUserInteraction()方法  
  4.         //是个空的方法, 我们直接跳过这里看下面的实现  
  5.         if (ev.getAction() == MotionEvent.ACTION_DOWN) {  
  6.             onUserInteraction();  
  7.         }  
  8.           
  9.         if (getWindow().superDispatchTouchEvent(ev)) {  
  10.             return true;  
  11.         }  
  12.           
  13.         //getWindow().superDispatchTouchEvent(ev)返回false,这个事件就交给Activity  
  14.         //来处理, Activity的onTouchEvent()方法直接返回了false  
  15.         return onTouchEvent(ev);  
  16.     }  
这个方法中我们还是比较关心getWindow()的superDispatchTouchEvent()方法,getWindow()返回当前Activity的顶层窗口Window对象,我们直接看Window API的superDispatchTouchEvent()方法

[java]  view plain  copy
 
  1. /** 
  2.      * Used by custom windows, such as Dialog, to pass the touch screen event 
  3.      * further down the view hierarchy. Application developers should 
  4.      * not need to implement or call this. 
  5.      * 
  6.      */  
  7.     public abstract boolean superDispatchTouchEvent(MotionEvent event);  
这个是个抽象方法,所以我们直接找到其子类来看看superDispatchTouchEvent()方法的具体逻辑实现,Window的唯一子类是PhoneWindow,我们就看看PhoneWindow的superDispatchTouchEvent()方法

[java]  view plain  copy
 
  1. public boolean superDispatchTouchEvent(KeyEvent event) {  
  2.         return mDecor.superDispatcTouchEvent(event);  
  3.     }  
里面直接调用DecorView类的superDispatchTouchEvent()方法,或许很多人不了解DecorView这个类,DecorView是PhoneWindow的一个final的内部类并且继承FrameLayout的,也是Window界面的最顶层的View对象,这是什么意思呢?别着急,我们接着往下看


我们先新建一个项目,取名AndroidTouchEvent,然后直接用模拟器运行项目, MainActivity的布局文件为

[html]  view plain  copy
 
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     tools:context=".MainActivity" >  
  6.   
  7.     <TextView  
  8.         android:layout_width="wrap_content"  
  9.         android:layout_height="wrap_content"  
  10.         android:layout_centerHorizontal="true"  
  11.         android:layout_centerVertical="true"  
  12.         android:text="@string/hello_world" />  
  13.   
  14. RelativeLayout>  
利用hierarchyviewer工具来查看下MainActivity的View的层次结构,如下图


PHPer年薪30万必修课程
【点击进入】
只为高端PHP而设计 三个月成就PHP达人!



我们看到最顶层就是PhoneWindow$DecorView,接着DecorView下面有一个LinearLayout, LinearLayout下面有两个FrameLayout

上面那个FrameLayout是用来显示标题栏的,这个Demo中是一个TextView,当然我们还可以定制我们的标题栏,利用getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,R.layout.XXX); xxx就是我们自定义标题栏的布局XML文件
下面的FrameLayout是用来装载ContentView的,也就是我们在Activity中利用setContentView()方法设置的View,现在我们知道了,原来我们利用setContentView()设置Activity的View的外面还嵌套了这么多的东西

我们来理清下思路,Activity的最顶层窗体是PhoneWindow,而PhoneWindow的最顶层View是DecorView,接下来我们就看DecorView类的superDispatchTouchEvent()方法

[java]  view plain  copy
 
  1. public boolean superDispatchTouchEvent(MotionEvent event) {  
  2.             return super.dispatchTouchEvent(event);  
  3.         }  
在里面调用了父类FrameLayout的dispatchTouchEvent()方法,而FrameLayout中并没有dispatchTouchEvent()方法,所以我们直接看ViewGroup的dispatchTouchEvent()方法
[java]  view plain  copy
 
  1. /** 
  2.     * {@inheritDoc} 
  3.     */  
  4.    @Override  
  5.    public boolean dispatchTouchEvent(MotionEvent ev) {  
  6.        final int action = ev.getAction();  
  7.        final float xf = ev.getX();  
  8.        final float yf = ev.getY();  
  9.        final float scrolledXFloat = xf + mScrollX;  
  10.        final float scrolledYFloat = yf + mScrollY;  
  11.        final Rect frame = mTempRect;  
  12.   
  13.        //这个值默认是false, 然后我们可以通过requestDisallowInterceptTouchEvent(boolean disallowIntercept)方法  
  14.        //来改变disallowIntercept的值  
  15.        boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;  
  16.   
  17.        //这里是ACTION_DOWN的处理逻辑  

你可能感兴趣的:(View,ViewGroup的Touch事件的分发机制)