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

摘要:
昨天,我们做了一些事情来实现接触事件冲突,我们过去经常遇到事件冲突。我们突然想到,我们应该研究Android的事件冲突机制,所以从昨天到今天,我们需要全天了解这些知识,这样我们才能了解Android触摸和点击事件的机制。探索如下:首先为测试重写三个视图布局:packagecom.example.yzj。雄性8_10;importandroid.content。上下文重要的

  昨天做东西做到触摸事件冲突,以前也经常碰到事件冲突,想到要研究一下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类:ActivitydispatchTouchEvent();
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

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

android 事件分发机制详解(OnTouchListener,OnClick)第1张

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

 android 事件分发机制详解(OnTouchListener,OnClick)第2张

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

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

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

免责声明:文章转载自《android 事件分发机制详解(OnTouchListener,OnClick)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Studio 3T 重置试用日期API性能测试基本性能指标及要求下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

JavaScript内置一些方法的实现原理--new关键字,call/apply/bind方法--实现

先学习下new操作符吧 new关键字调用函数的心路历程: 1.创建一个新对象 2.将函数的作用域赋给新对象(this就指向这个对象) 3.执行函数中的代码 4.返回这个对象 根据这个的思路,来实现一个简单的new操作吧,代码演示: 1 function myNew(Func, ...args) { 2 if (typeof Func !== 'fu...

跨站请求伪造(CSRF)

1. 什么是跨站请求伪造(CSRF)   CSRF(Cross-site request forgery跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,并且攻击方式几乎相左。XSS利用站点内的信任用户,而...

一个漂亮而强大的RecyclerView

代码地址如下:http://www.demodashi.com/demo/13470.html 简介 主要提供了简单易用强大的RecyclerView库,包括自定义刷新加载效果、极简通用的万能适配器Adapter、万能分割线、多种分组效果、常见状态页面、item动画效果、添加多个header和footer、侧滑、拖拽、Sticky(黏性)效果、多item布...

go-grpc 基本使用

gRPC是什么? gRPC是什么可以用官网的一句话来概括 A high-performance, open-source universal RPC framework 所谓RPC(remote procedure call 远程过程调用)框架实际是提供了一套机制,使得应用程序之间可以进行通信,而且也遵从server/client模型。使用的时候客户端调用...

canvas基础—图形变换

1、canvas转换方法 1.1canvas转换方法 二、canvas实现图形的中心点旋转 step1:获取canva元素并指定canvas的绘图环境 var canvas=document.getElementById('canvas'); var context=canvas.getContext('2d'); step2:在画布(1...

给HttpClient添加Socks代理

本文描述http client使用socks代理过程中需要注意的几个方面:1,socks5支持用户密码授权;2,支持https;3,支持让代理服务器解析DNS; 使用代理创建Socket 从原理上来看,不管用什么http客户端(httpclient,okhttp),最终都要转换到java.net.Socket的创建上去,看到代码: package java...