浅析Android事件传递机制

《浣溪沙》

一向年光有限身,等闲离别易销魂,酒筵歌席莫辞频。
满目山河空念远,落花风雨更伤春,不如怜取眼前人。

直奔主题之前需要做两件事:
1 普及一下Android MotionEvent事件处理的知识
众所周知我们用手点击屏幕又放开手这中间经历了一共三个过程(手指按下—手指贴在屏幕上移动—手指抬起),对应在Android中就是三个MotionEvent手势动作(ACTION_DOWN,ACTION_MOVE, ACTION_UP)。当用户触摸屏幕时将创建一个MotionEvent对象。MotionEvent包含关于发生触摸的位置和时间等细节信息,MotionEvent对象被传递到程序中合适的方法中,在这些方法中我们可以分析MotionEvent对象是三种手势动作中的哪一种,以决定要执行的操作。

2 打开下面的传送门先自行理解一波

Android Touch事件传递机制通俗讲解

以上两点你只需要大致了解即可,接下来我开讲~~
这里写图片描述
上图是我们手机屏幕中的三个部分,A表示Activity,B表示A中的一个ViewGroup,而C表示B中的一个View,当我们用手点击C区域内时,我们都知道是C被点击了但是B和A都没有反应,可是明明AB都包括了C,AB都应该被点击了但是为什么AB却没有反应呢?
原来这是因为Android内部存在一种事件传递机制
请仔细看下图!
请仔细看下图!
请仔细看下图!
流程图
图中有三个方法:

dispatchTouchEvent()      用于分发触摸事件  返回true表示事件被消费不传递了
onInterceptTouchEvent ( ) 用于拦截触摸事件  返回true表示事件被拦截不向下传递而是调用本组件的onTouchEvent方法

onTouchEvent ()           用于消费触摸事件  返回true表示事件被消费不传递了

我举个通俗的例子来解释这个过程
“有个人是省长的朋友(MotionEvent)想找省长(A)办事,省长答应的很爽快可是虽然省长权力很大但是不会做具体的活,于是就把具体的执行过程交给(dispatchTouchEvent)了我们的好市长(B),市长看到了任务觉得这件事我做是能做但是太麻烦了,我到底要不要自己做呢?就在哪里犹豫来犹豫去(onInterceptTouchEvent),最后市长觉得太麻烦还是让自己的下级去做吧,于是把任务交给(dispatchTouchEvent)了我的好县长©,C县长已经是最低级了,如果这件事C自己努力了做出来了(onTouchEvent),整个事情结束,如果C也做不出来就向上级B反应说自己无能为力,B不得不自己做了,如果B发现自己也做不了那就继续反应A说自己无能为力,最后这个事还给了A让A自己做”

因为实践出真知,接下来我用代码和截图给大家解释一下:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.liang.MainActivity">
   <com.liang.MyGroup
       android:id="@+id/group"
       android:layout_width="200dp"
       android:layout_height="200dp"
       android:orientation="horizontal"
       android:weightSum="1"
       android:layout_centerVertical="true"
       android:layout_centerHorizontal="true">

       <com.liang.MyTextView
           android:id="@+id/View"
           android:layout_centerInParent="true"
           android:gravity="center"
           android:layout_height="100dp"
           android:layout_width="100dp"
           android:text="Hello World!"/>
   </com.liang.MyGroup>
</RelativeLayout>
package com.liang;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.RelativeLayout;

/**
 * Created by Administrator on 2017/3/5.
 */

public class MyGroup extends RelativeLayout {
    public MyGroup(Context context) {
        super(context);
    }

    public MyGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.i("TAG","viewGroup dispatchTouchEvent "+TestUtils.whichAction(ev));
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.i("TAG","viewGroup onInterceptTouchEvent "+TestUtils.whichAction(ev));
        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i("TAG","viewGroup onTouchEvent "+TestUtils.whichAction(event));
        return super.onTouchEvent(event);
    }
}

package com.liang;

import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;

/**
 * Created by Administrator on 2017/3/5.
 */

public class MyTextView extends android.support.v7.widget.AppCompatTextView {
    public MyTextView(Context context) {
        super(context);
    }

    public MyTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MyTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.i("TAG","view dispatchTouchEvent "+TestUtils.whichAction(event));
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i("TAG","view onTouchEvent "+TestUtils.whichAction(event));
        return super.onTouchEvent(event);
    }
}

package com.liang;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private RelativeLayout mRelativeLayout;
    private TextView mTextView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRelativeLayout = (RelativeLayout) findViewById(R.id.group);
        mTextView = (TextView) findViewById(R.id.View);
        mRelativeLayout.setOnClickListener(this);
        mTextView.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.group:
                Toast.makeText(this, "布局被点击", Toast.LENGTH_SHORT).show();
                break;
            case R.id.View:
                Toast.makeText(this, "视图被点击", Toast.LENGTH_SHORT).show();
                break;
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
             Log.i("TAG","activity dispatchTouchEvent "+TestUtils.whichAction(ev));
            return super.dispatchTouchEvent(ev);
    }

}

整个事件传递的流程就大致讲完了,最后我留个问题哈,我实际项目中运行的log信息是这样的:
这里写图片描述

为什么这个事件传递被执行了两次呢?是不是每一次ACTION_DOWN和ACTION_UP都执行相同的次数呢?

想知道这个问题的答案请看这里:

分发机制的细节

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值