• android 事件分发机制详解(OnTouchListener,OnClick)


      昨天做东西做到触摸事件冲突,以前也经常碰到事件冲突,想到要研究一下Android的事件冲突机制,于是从昨天开始到今天整整一天时间都要了解这方面的知识,这才懂了安卓的触摸和点击事件的机制。探究如下:

      首先重写三个View布局,用来做测试:

        

    package com.example.yzj.android_8_10;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.widget.LinearLayout;
    
    /**
     * Created by YZJ on 2016/8/10.
     */
    public class V1 extends LinearLayout{
    
    
        public V1(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            Log.v("msg", "v1-dispatch");
            return super.dispatchTouchEvent(ev);
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            Log.v("msg","v1-onIntercept");
            return false;
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            Log.v("msg","v1-onTouch");
            return false;
        }
    }
    package com.example.yzj.android_8_10;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.LinearLayout;
    
    /**
     * Created by YZJ on 2016/8/10.
     */
    public class V2 extends LinearLayout{
    
        public V2(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            Log.v("msg", "v2-dispatch");
            return super.dispatchTouchEvent(ev);
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            Log.v("msg","v2-onIntercept");
            return false;
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            Log.v("msg","v2-onTouch");
            return false;
        }
    }
    package com.example.yzj.android_8_10;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    
    /**
     * Created by YZJ on 2016/8/10.
     */
    public class V3 extends View {
    
        public V3(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            Log.v("msg", "v3-dispatch");
            return super.dispatchTouchEvent(ev);
        }
    //    @Override
    //    public boolean onTouchEvent(MotionEvent event) {
    //        Log.v("msg","v3-onTouch");
    //        return true;
    //    }
    }

    然后是MainActivity的xml代码:

    <?xml version="1.0" encoding="utf-8"?>
    <com.example.yzj.android_8_10.V1 xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/v1"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/colorAccent"
        tools:context="com.example.yzj.android_8_10.MainActivity">
        <com.example.yzj.android_8_10.V2
            android:layout_gravity="center"
            android:id="@+id/v2"
            android:layout_width="400dp"
            android:layout_height="400dp"
            android:background="@color/colorPrimaryDark">
            <com.example.yzj.android_8_10.V3
                android:background="#F00000"
                android:id="@+id/v3"
                android:layout_gravity="center"
                android:layout_width="300dp"
                android:layout_height="300dp"></com.example.yzj.android_8_10.V3>
        </com.example.yzj.android_8_10.V2>
    </com.example.yzj.android_8_10.V1>

        

      然后是MainActivity的JAVA代码:

      

    package com.example.yzj.android_8_10;
    
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    
    
    public class MainActivity extends AppCompatActivity {
        View v1, v2, v3;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            init();
        }
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            Log.v("msg", "MainActivity-dispatch");
            return super.dispatchTouchEvent(ev);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            Log.v("msg", "MainActivity-onTouch");
            return false;
        }
    
        private void init() {
            v1 = findViewById(R.id.v1);
            v2 = findViewById(R.id.v2);
            v3 = findViewById(R.id.v3);
            v3.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    switch(event.getAction()){
                        case MotionEvent.ACTION_DOWN:
                            Log.v("msg","Action_Down");
                            break;
                        case MotionEvent.ACTION_MOVE:
                            Log.v("msg","Action_Move");
                            break;
                        case MotionEvent.ACTION_UP:
                            Log.v("msg","Action_Up");
                            break;
                    }
                    return false;
                }
            });
          v3.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View v) {
                  Log.v("msg","v3-OnClick");
              }
          });
        }
    }

      下面来详细说明:

          Android的触摸和点击事件其实是绑定在一起的,或者说的更详细一点OnClick是依赖于OnTouch的,这点在稍后会详细的说明。先介绍一下消息传递的流程,Android和WINDOWS的消息传递机制是一样的,都是冒泡传递,即从最底层,往上依次传递,在我的代码中是从MainActivity->v1->v2->v3,这样传递消息,而处理起来,或者用专业术语叫消费(google的API文档中是用消费这个词...),消费则是相反的方向,即从上面最小的V3开始,逐渐传递到MainActivity,v3->v2->v1->MainActivity.

    下面附上代码运行的结果:

          //事件传递过程

    08-10 17:40:06.182 3926-3926/? V/msg: MainActivity-dispatch
    08-10 17:40:06.182 3926-3926/? V/msg: v1-dispatch
    08-10 17:40:06.182 3926-3926/? V/msg: v1-onIntercept
    08-10 17:40:06.182 3926-3926/? V/msg: v2-dispatch
    08-10 17:40:06.182 3926-3926/? V/msg: v2-onIntercept
    08-10 17:40:06.182 3926-3926/? V/msg: v3-dispatch

          //事件消费过程
    08-10 17:40:06.182 3926-3926/? V/msg: v3-OnTouch
    08-10 17:40:06.182 3926-3926/? V/msg: v2-onTouch
    08-10 17:40:06.182 3926-3926/? V/msg: v1-onTouch
    08-10 17:40:06.182 3926-3926/? V/msg: MainActivity-onTouch

    可以清楚的看出,事件的传递过程的方向和消费过程的方向。

      

        

    跟touch事件相关的3个方法:
    public boolean dispatchTouchEvent(MotionEvent ev);    //用来分派event
    public boolean onInterceptTouchEvent(MotionEvent ev); //用来拦截event
    public boolean onTouchEvent(MotionEvent ev);          //用来处理event
    Activity类: Activity dispatchTouchEvent();
    onTouchEvent();
    View容器(ViewGroup的子类): FrameLayout、LinearLayout……
    ListView、ScrollVIew……
    dispatchTouchEvent();
    onInterceptTouchEvent();
    onTouchEvent();
    View控件(非ViewGroup子类): Button、TextView、EditText…… dispatchTouchEvent();
    onTouchEvent();

       

    个方法的用法:
     
     
     
     
     
    dispatchTouchEvent() 用来分派事件。
    其中调用了onInterceptTouchEvent()和onTouchEvent(),一般不重写该方法
    onInterceptTouchEvent() 用来拦截事件。
    ViewGroup类中的源码实现就是{return false;}表示不拦截该事件,
    事件将向下传递(传递给其子View);
    若手动重写该方法,使其返回true则表示拦截,事件将终止向下传递,
    事件由当前ViewGroup类来处理,就是调用该类的onTouchEvent()方法
    onTouchEvent() 用来处理事件。
    返回true则表示该View能处理该事件,事件将终止向上传递(传递给其父View);
    返回false表示不能处理,则把事件传递给其父View的onTouchEvent()方法来处理
          
     
     
     
              下面在把ACION_DOWN,MOVE,UP,ONCLICK的顺序写下来,测试结果如下:

    08-10 17:49:30.182 5125-5125/? V/msg: MainActivity-dispatch
    08-10 17:49:30.182 5125-5125/? V/msg: v1-dispatch
    08-10 17:49:30.182 5125-5125/? V/msg: v1-onIntercept
    08-10 17:49:30.182 5125-5125/? V/msg: v2-dispatch
    08-10 17:49:30.182 5125-5125/? V/msg: v2-onIntercept
    08-10 17:49:30.182 5125-5125/? V/msg: v3-dispatch
    08-10 17:49:30.182 5125-5125/? V/msg: Action_Down
    08-10 17:49:30.182 5125-5125/? V/msg: v2-onTouch
    08-10 17:49:30.182 5125-5125/? V/msg: v1-onTouch
    08-10 17:49:30.182 5125-5125/? V/msg: MainActivity-onTouch
    08-10 17:49:30.202 5125-5125/? V/msg: MainActivity-dispatch
    08-10 17:49:30.202 5125-5125/? V/msg: MainActivity-onTouch
    08-10 17:49:30.232 5125-5125/? V/msg: MainActivity-dispatch
    08-10 17:49:30.232 5125-5125/? V/msg: MainActivity-onTouch
    08-10 17:49:30.242 5125-5125/? V/msg: MainActivity-dispatch
    08-10 17:49:30.242 5125-5125/? V/msg: MainActivity-onTouch

          最后借鉴几张别人总结的好图,可以更直观的看:

            如果在V3处ONTOUCH返回的flase,那么 

     

        其他的几种情况请读者自己测试,本文就写到这里。

          在此感谢http://blog.csdn.net/morgan_xww/article/details/9372285/给我的提示。

          希望大家自己测试一下,毕竟自己亲手动过的记得比较牢。

  • 相关阅读:
    1CSS与文档
    14交互活动:XHTML表单
    13开始制作表格:表格和列表
    12布置元素:布局和排版
    11高级网站构建:div和span
    10与元素亲密接触:盒元素(the box model)
    tp5.1 与vue ajax请求跨域的问题
    小程序父子组件互相传参,互相调用方法
    PHP/js数组与字符串的操作,字符串转数组,数组转字符串,去掉字符串最后一个字符,判断二维数组是否为空等
    easyui datagrid分页栏位置问题
  • 原文地址:https://www.cnblogs.com/yzjT-mac/p/yzj_android.html
Copyright © 2020-2023  润新知