zoukankan      html  css  js  c++  java
  • Android笔记:触摸事件的分析与总结----TouchEvent处理机制

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://glblong.blog.51cto.com/3058613/1559320

       其他相关博文:

       Android笔记:触摸事件的分析与总结----MotionEvent对象

       Android笔记:触摸事件的分析与总结----TouchEvent处理机制

        Android中的事件类型分为按键事件和屏幕触摸事件。TouchEvent是屏幕触摸事件的基础事件,要深入了解屏幕触摸事件的处理机制,就必须掌握TouchEvent在整个触摸事件中的转移和处理过程。此处将对TouchEvent处理机制的学习做个小小的总结和备记。

        当屏幕中包含一个ViewGroup,而这个ViewGroup又包含一个子view,这个时候android系统如何处理Touch事件呢?到底是 ViewGroup来处理Touch事件,还是子view来处理Touch事件呢?

        这问题涉及到与每个View或者ViewGroup的子类都具有的三个和TouchEvent处理密切相关的方法:

    1)dispatchTouchEvent(MotionEvent ev)     这个方法用来分发TouchEvent

    2)onInterceptTouchEvent(MotionEvent ev)  这个方法用来拦截TouchEvent

    3)onTouchEvent(MotionEvent ev)           这个方法用来处理TouchEvent

        其中view类和Activity中都有dispatchTouchEvent()和onTouchEvent()两个方法。ViewGroup继承自View,而且还新添了一个onInterceptTouchEvent()方法。

        这三个方法的返回值都是boolean值,对于返回结果,如果return true,那么表示该方法消费了此次事件,如果return false,那么表示该方法并未处理完全,该事件仍然需要以某种方式传递下去继续等待处理。

    一、dispatchTouchEvent

        dispatchTouchEvent(MotionEventev) 这个方法用来分发TouchEvent,默认返回false。

        先看下Activity中的注释和方法:

       /**
         * Called to process touch screen events.  You can override this to
         * intercept all touch screen events before they are dispatched to the
         * window.  Be sure to call this implementation for touch screen events
         * that should be handled normally.
         * 
         * @param ev The touch screen event.
         * 
         * @return boolean Return true if this event was consumed.
         */
        public boolean dispatchTouchEvent(MotionEvent ev)
        {
            if (ev.getAction() == MotionEvent.ACTION_DOWN)
            {
                onUserInteraction();
            }
            if (getWindow().superDispatchTouchEvent(ev))
            {
                return true;
            }
            return onTouchEvent(ev);
        }

    onInterceptTouchEvent()默认返回了false,注释的大意为重写该方法可以实现对触屏事件的拦截,使用该方法需要特别注意的是,该方法与View类的onTouchEvent(MotionEvent)或者View.onTouchEvent(MotionEvent)方法具有复杂的关联机制。结合onTouchEvent(),总结下onInterceptTouchEvent()大致的规则为:

    1. down事件首先会传递到onInterceptTouchEvent()方法。

    2. 如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return false,那么后续的move, up等事件将继续会先传递给该ViewGroup,之后才和down事件一样传递给最终的目标View的onTouchEvent()处理。

    3. 如果该ViewGroup的onInterceptTouchEvent()在接收到down事件处理完成之后return true,那么后续的move, up等事件将不再传递给onInterceptTouchEvent(),而是和down事件一样传递给该ViewGroup的onTouchEvent()处理,注意,目标view将接收不到任何事件。

    4. 如果最终需要处理事件的view的onTouchEvent()返回了false,那么该事件将被传递至其上一层次的view的onTouchEvent()处理。

    5. 如果最终需要处理事件的view 的onTouchEvent()返回了true,那么后续事件将可以继续传递给该view的onTouchEvent()处理。

    三、onTouchEvent

        onTouchEvent()的处理机制详见此文:

        Android笔记:触摸事件的分析与总结----MotionEvent对象

    四、TouchEvent处理范例

        此处创建一个包含自定义LinearLayout(ViewGroup类)和自定义TextView(View类)的Activity来分析触摸屏幕时TouchEvent的处理机制。

        效果图如下:

    wKiom1Qj1aTiY14EAACGBwMjfvc945.jpg

    <?xml version="1.0" encoding="utf-8"?> 
    <com.example.d_touchevent.MyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
        android:orientation="vertical" 
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent" 
        android:gravity="center" > 
           <com.example.d_touchevent.MyTextView 
                android:layout_width="100dp" 
                android:layout_height="100dp" 
                android:id="@+id/tv" 
                android:text="测试" 
                android:textSize="40sp" 
                android:textStyle="bold" 
                android:background="#F0F00F" 
                android:textColor="#0000FF"/> 
    </com.example.d_touchevent.MyLinearLayout>

      MainActivity.java代码如下:

    package com.example.d_touchevent;
     
    import android.os.Bundle;
    import android.app.Activity;
    import android.util.Log;
    import android.view.MotionEvent;
     
    /**
     * 参考资料:http://glblong.blog.51cto.com/3058613/1559320
     * @author zeng
     *
     */
    public class MainActivity extends Activity
    {
        private String TAG = "Activity ---  ";
     
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
         
        @Override
        public boolean onTouchEvent(MotionEvent event)
        {
            boolean b = super.onTouchEvent(event);
             
             
            int action = event.getAction();
             
            switch (action)
            {
             
                case MotionEvent.ACTION_DOWN:
                    Log.e(TAG , "ACTION_DOWN   --- " + TAG + "onTouchEvent          处理 --- " + b);
                     
                    break;
                 
                case MotionEvent.ACTION_MOVE:
                     
                    Log.e(TAG, "ACTION_MOVE    --- " + TAG + "onTouchEvent          处理 --- " + b);
                     
                    break;
                 
                case MotionEvent.ACTION_UP:
                     
                    Log.e(TAG, "ACTION_UP     --- " + TAG + "onTouchEvent          处理 --- " + b);
                     
                    break;
                 
                case MotionEvent.ACTION_CANCEL:
                     
                    Log.e(TAG, "ACTION_CANCEL --- " + TAG + "onTouchEvent          处理 --- " + b);
                     
                    break;
             
            }
             
             
            return b;
        }
         
         
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev)
        {
            int action = ev.getAction();
             
            switch (action)
            {
             
                case MotionEvent.ACTION_DOWN:
                    Log.e(TAG, "ACTION_DOWN   --- " + TAG + "dispatchTouchEvent    分发 --- ");
                     
                    break;
                 
                case MotionEvent.ACTION_MOVE:
                     
                    Log.e(TAG, "ACTION_MOVE   --- " + TAG + "dispatchTouchEvent    分发 --- ");
                     
                    break;
                 
                case MotionEvent.ACTION_UP:
                     
                    Log.e(TAG, "ACTION_UP     --- " + TAG + "dispatchTouchEvent    分发 --- ");
                     
                    break;
                 
                case MotionEvent.ACTION_CANCEL:
                     
                    Log.e(TAG, "ACTION_CANCEL --- " + TAG + "dispatchTouchEvent    分发 --- ");
                     
                    break;
             
            }
            return super.dispatchTouchEvent(ev);
        }
         
    }

    MyLinearLayout.java代码如下:

    package com.example.d_touchevent;
     
    import android.widget.LinearLayout;
    import android.content.Context;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
     
    /**
     * 参考资料:http://glblong.blog.51cto.com/3058613/1559320
     * @author zeng
     *
     */
    public class MyLinearLayout extends LinearLayout
    {
        private final String TAG = "L布局    ---  ";
         
        public MyLinearLayout(Context context, AttributeSet attrs)
        {
            super(context, attrs);
             
            Log.e(TAG, TAG);
        }
         
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev)
        {
            int action = ev.getAction();
             
            switch (action)
            {
             
                case MotionEvent.ACTION_DOWN:
                    Log.e("", " ");
                    Log.e("", " ");
                    Log.e(TAG, "ACTION_DOWN   --- " + TAG + "dispatchTouchEvent    分发 --- ");
                     
                    break;
                 
                case MotionEvent.ACTION_MOVE:
                     
                    Log.e(TAG, "ACTION_MOVE   --- " + TAG + "dispatchTouchEvent    分发 --- ");
                     
                    break;
                 
                case MotionEvent.ACTION_UP:
                     
                    Log.e(TAG, "ACTION_UP     --- " + TAG + "dispatchTouchEvent    分发 --- ");
                     
                    break;
                 
                case MotionEvent.ACTION_CANCEL:
                     
                    Log.e(TAG, "ACTION_CANCEL --- " + TAG + "dispatchTouchEvent    分发 --- ");
                     
                    break;
             
            }
            return super.dispatchTouchEvent(ev);
        }
         
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev)
        {
            boolean b = false;
             
            int action = ev.getAction();
            switch (action)
            {
             
                case MotionEvent.ACTION_DOWN:
                     
                    Log.e(TAG, "ACTION_DOWN   --- " + TAG + "onInterceptTouchEvent 拦截 --- " + b);
                     
                    break;
                 
                case MotionEvent.ACTION_MOVE:
                     
                    Log.e(TAG, "ACTION_MOVE   --- " + TAG + "onInterceptTouchEvent 拦截 --- " + b);
                     
                    break;
                 
                case MotionEvent.ACTION_UP:
                     
                    Log.e(TAG, "ACTION_UP     --- " + TAG + "onInterceptTouchEvent 拦截 --- " + b);
                     
                    break;
                 
                case MotionEvent.ACTION_CANCEL:
                     
                    Log.e(TAG, "ACTION_CANCEL --- " + TAG + "onInterceptTouchEvent 拦截 --- " + b);
                     
                    break;
             
            }
             
            return b;
             
        }
         
        @Override
        public boolean onTouchEvent(MotionEvent ev)
        {
            boolean b = true;
             
            int action = ev.getAction();
            switch (action)
            {
             
                case MotionEvent.ACTION_DOWN:
                     
                    Log.e(TAG, "ACTION_DOWN   --- " + TAG + "onTouchEvent          处理 --- " + b);
                     
                    break;
                 
                case MotionEvent.ACTION_MOVE:
                     
                    Log.e(TAG, "ACTION_MOVE   --- " + TAG + "onTouchEvent          处理 --- " + b);
                     
                    break;
                 
                case MotionEvent.ACTION_UP:
                     
                    Log.e(TAG, "ACTION_UP     --- " + TAG + "onTouchEvent          处理 --- " + b);
                     
                    break;
                 
                case MotionEvent.ACTION_CANCEL:
                     
                    Log.e(TAG, "ACTION_CANCEL --- " + TAG + "onTouchEvent          处理 --- " + b);
                     
                    break;
             
            }
             
            return b;
        }
    }

    MyTextView.java代码如下:

    package com.example.d_touchevent;
     
    import android.widget.TextView;
    import android.content.Context;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
     
    /**
     * 参考资料:http://glblong.blog.51cto.com/3058613/1559320
     * @author zeng
     *
     */
    public class MyTextView extends TextView
    {
        private final String TAG = "TextView ---  ";
         
        public MyTextView(Context context, AttributeSet attrs)
        {
            super(context, attrs);
        }
         
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev)
        {
            int action = ev.getAction();
             
            switch (action)
            {
             
                case MotionEvent.ACTION_DOWN:
                     
                    Log.e(TAG, "ACTION_DOWN   --- " + TAG + "dispatchTouchEvent    分发 --- ");
                     
                    break;
                 
                case MotionEvent.ACTION_MOVE:
                     
                    Log.e(TAG, "ACTION_MOVE   --- " + TAG + "dispatchTouchEvent    分发 --- ");
                     
                    break;
                 
                case MotionEvent.ACTION_UP:
                     
                    Log.e(TAG, "ACTION_UP     --- " + TAG + "dispatchTouchEvent    分发 --- ");
                     
                    break;
                 
                case MotionEvent.ACTION_CANCEL:
                     
                    Log.e(TAG, "ACTION_CANCEL --- " + TAG + "dispatchTouchEvent    分发 --- ");
                     
                    break;
             
            }
            return super.dispatchTouchEvent(ev);
        }
         
        @Override
        public boolean onTouchEvent(MotionEvent ev)
        {
            boolean b = false;
             
            int action = ev.getAction();
            switch (action)
            {
                case MotionEvent.ACTION_DOWN:
                    Log.e(TAG, "ACTION_DOWN   --- " + TAG + "onTouchEvent          处理 --- " + b);
                     
                    break;
                 
                case MotionEvent.ACTION_MOVE:
                     
                    Log.e(TAG, "ACTION_MOVE   --- " + TAG + "onTouchEvent          处理 --- " + b);
                     
                    break;
                 
                case MotionEvent.ACTION_UP:
                     
                    Log.e(TAG, "ACTION_UP     --- " + TAG + "onTouchEvent          处理 --- " + b);
                     
                    break;
                 
                case MotionEvent.ACTION_CANCEL:
                     
                    Log.e(TAG, "ACTION_CANCEL --- " + TAG + "onTouchEvent          处理 --- " + b);
                     
                    break;
             
            }
             
            return b;
             
        }
         
     
    }

    五、范例运行分析

        注:a.以下Logcat中,若没有特别说明,dispatchTouchEvent()都按默认方法返回false。    

           b.为方便,L布局简写为L,TextView简写为T,Activity简写为A,下同。

        1)点击范例中的【测试】按钮,运行日志如下:

    wKioL1Qj1u6AUjd2AALSLhLP6vA025.jpg

        结论:

        当ACTION_DOWN事件产生时,首先触发了Activity的dispatchTouchEvent()方法;接着传递到ViewGroup上,触发L布局的dispatchTouchEvent()方法继续分发TouchEvent;L布局的onInterceptTouchEvent()方法为false,即不会拦截TouchEvent的传递,因而继续传递到ViewGroup里的View对象TextView中,此时仍然先是调用了TextView的dispatchTouchEvent()方法来处理TouchEvent的分发。从上到下依次传递:Activity -> L布局 -> TextView。

        同理,当ACTION_UP事件产生时,首先也是Activity的dispatchTouchEvent()方法,接着再到L布局的dispatchTouchEvent()方法。

         

        2)L.dispatchTouchEvent() = true ,运行日志如下:

    wKioL1Qj1y3gNZAUAAGG5oMOlwY678.jpg

       结论:

       此时,每个触摸事件产生时,都只执行到L布局的dispatchTouchEvent()方法,而不会继续再传递并触发其他方法。

        

        3)A.dispatchTouchEvent() = false  &&  L.dispatchTouchEvent() = false  &&  T.dispatchTouchEvent() = true,运行日志如下:

    wKiom1Qj1yqAJ1fMAAKa1HHWNC4703.jpg

        结论:

        由上可见,当TouchEvent由Activity传递到TextView时,执行到dispatchTouchEvent()后便结束了。也就是到TextView时,Android系统认为ACTION_DOWN和ACITON_UP都已经被消费了,而没有继续分发下去。

        4)L.onInterceptTouchEvent = true   &&   L.onTouchEvent = true ,运行日志如下:

    wKiom1Qj10Tyr1MpAAObyesw05M744.jpg

        结论:

        这种情况下,L布局处理了所有的TouchEvent。

        5)L.onInterceptTouchEvent = true   &&   L.onTouchEvent = false , 运行日志如下:

    wKioL1Qj1_PCsV5oAAO3Omd7D88812.jpg

       结论:

        L布局只处理了ACTION_DOWN事件,而L布局最外层的ctivity处理了TouchEvent。

        6)L.onInterceptTouchEvent=false  &&  L.onTouchEvent=true  &&  T.onTouchEvent=true , 运行日志如下:

    wKiom1Qj2DnTyBMeAASIoe2a38s538.jpg

        结论:

        TouchEvent完全由TextView处理。

        7)L.onInterceptTouchEvent=false  &&  L.onTouchEvent=true  &&  T.onTouchEvent=false , 运行日志如下:

    wKioL1Qj2IewoeuaAATViItVS0Y803.jpg

         结论:

         TextView只处理了ACTION_DOWN事件,LinearLayout处理了所有的TouchEvent。

    六、分析总结

    1.三个主要相关的方法的默认值

    所有dispatchTouchEvent方法的默认值都是false。

    ViewGroup里的onInterceptTouchEvent默认值是false这样才能把事件传给View里的onTouchEvent.

    Activity和ViewGroup里的onTouchEvent默认值都是false。

    View里的onTouchEvent返回默认值是true.这样才能执行多次touch事件。

    2.TouchEvent的处理流程

    当TouchEvent发生时,首先Activity将TouchEvent传递给最顶层的View, TouchEvent最先到达最顶层 view 的 dispatchTouchEvent ,然后由  dispatchTouchEvent 方法进行分发,如果dispatchTouchEvent返回true ,则表示该触摸事件已经被消费了,如果dispatchTouchEvent返回 false ,则交给这个 view 的 interceptTouchEvent 方法来决定是否要拦截这个事件,如果 interceptTouchEvent 返回 true ,也就是拦截掉了,则交给它的 onTouchEvent 来处理,如果 interceptTouchEvent 返回 false ,那么就传递给子 view ,由子 view 的 dispatchTouchEvent 再来开始这个事件的分发。如果事件传递到某一层的子 view 的 onTouchEvent 上了,这个方法返回了 false ,那么这个事件会从这个 view 往上传递,都是 onTouchEvent 来接收。而如果传递到最上面的 onTouchEvent 也返回 false 的话,这个事件就会“   消失”,而且接收不到下一次事件。

    3.TouchEvent的处理流程图

    自己制作了个TouchEvent处理的流程图,方便理清TouchEvent事件在各种UI对象以及对应方法中的处理机制。将流程图与上面的运行日志结合分析,发现对TouchEvent处理的机制清晰了很多。若有错误之处,欢迎指教。

    wKioL1Qo01bh7FokAAKn6n5a4u0915.jpg

  • 相关阅读:
    Java调用存储过程
    Eclipse快捷键
    [转载]实现GridView手动设定分页
    给博客换了个皮肤
    在Hibernate中使用Oracle的sequence主键
    解决Oracle 10g中The account lockde!
    [转载]CSS的优化与技巧
    PowerDesigner12 简单应用
    【转载】用开源软件搭建企业内部协作平台, Kill QQ MSN
    DropDownList数据绑定第一项为空
  • 原文地址:https://www.cnblogs.com/xiaorenwu702/p/4018608.html
Copyright © 2011-2022 走看看