浅谈android事件分发机制

2 篇文章 0 订阅

浅谈android事件分发机制

最近准备换项目,因此需要重新回顾一下一些知识点,其中就包含事件分发机制,

先说说什么是事件分发机制,简单点说事件分发机制就是“将点击事件(MotionEvent)传递到某个具体的View & 处理的整个过程“,注意”过程“这俩个字

看别人的再多东西,不如自己上手来一遍,写个简单的demo然后我们来学习下事件分发机制。以下是代码准备

import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("ssssssssssEvent","Activity:dispatchTouchEvent");
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("ssssssssssEvent","Activity:onTouchEvent");
        return false;
    }
}

 

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

import androidx.annotation.Nullable;

public class MyLinearLayout extends LinearLayout {

    public MyLinearLayout(Context context) {
        super(context);
    }

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

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("ssssssssssEvent","MyLinearLayout:dispatchTouchEvent");
        return  super.dispatchTouchEvent(ev);
//        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("ssssssssssEvent","MyLinearLayout:onTouchEvent");
        return false;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e("ssssssssssEvent","MyLinearLayout:onInterceptTouchEvent");
        return false;
    }
}

 

 

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

public class MyButton extends Button {
    public MyButton(Context context) {
        super(context);
    }

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

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.e("ssssssssssEvent","MyButton:dispatchTouchEvent");
        return  super.dispatchTouchEvent(event);
//        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("ssssssssssEvent","MyButton:onTouchEvent");
        return false;
    }
}

 

<?xml version="1.0" encoding="utf-8"?>
<com.example.myapplication.MyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <com.example.myapplication.MyButton
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:id="@+id/btn_btn"
        android:text="按钮" />
    
</com.example.myapplication.MyLinearLayout>

 

 

代码呢就这么多,运行一下观察log,

不难看出,所有都按照正常流程走的话,事件会先从Activity 的dispatchTouchEvent开始向下分发,然后走到Viewgroup的dispatchTouchEvent方法中,然后重点来了"onInterceptTouchEvent"这个方法是做什么的呢,我们先留个悬念,接着往下走,然后事件分发到View的dispatchTouchEvent方法中,到这里dispatchTouchEvent向下分发就结束了,然后开始一层一层执行onTouchEvent方法,最终走到Activity的onTouchEvent方法中,这个是正常情况下的事件分发机制。

 

接着我们修改一下Activity中的dispatchTouchEvent,修改成下面这样子再观察log

   @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("ssssssssssEvent","Activity:dispatchTouchEvent");
//        return super.dispatchTouchEvent(ev);
        return true;
    }

很明显如果吧activity中的dispatchTouchEvent的返回值改为true,事件就不向下传递了,说明此次事件被activity自己消费了。

 

我们再来接着改下这几个地方,先把activity 的代码改回去

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    Log.e("ssssssssssEvent","Activity:dispatchTouchEvent");
    return super.dispatchTouchEvent(ev);
}

接着再改下viewgroup的dispatchTouchEvent代码,运行观察log,此时我们可以猜想一下,是不是結果应该是Activity的dispatchTouchEvent向下分发到ViewGroup的dispatchTouchEvent方法中,就停住了不再执行其他任何方法了?

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("ssssssssssEvent","MyLinearLayout:dispatchTouchEvent");
//        return  super.dispatchTouchEvent(ev);
        return true;
    }

結果果然和我们猜想的是一样的

此时我们就可以得到一个结论,dispatchTouchEvent方法的作用就是事件是否被消费,一旦被消费事件分发就到此而止了。

弄清楚了dispatchTouchEvent方法,还有两个函数onInterceptTouchEvent和onTouchEvent方法,别急我们接下来就来看这个两个个方法的作用

我们现在吧viewgroup的dispatchTouchEvent还原回去

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    Log.e("ssssssssssEvent","MyLinearLayout:dispatchTouchEvent");
    return  super.dispatchTouchEvent(ev);
}

再修改viewgroup的如下代码,并运行观察log

   @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e("ssssssssssEvent","MyLinearLayout:onInterceptTouchEvent");
//        return false;
        return true;
    }

我们可以看到这个时候不仅执行了onInterceptTouchEvent方法,而且还执行了viewgroup和activity的onTouchEvent方法,但是却没有执行的view的这两个方法,是不是我们就可以得出一个结论,onInterceptTouchEvent如果返回true的话,那么代表着整个事件分发机制被viewgroup响应,而不会再向下分发,因此onInterceptTouchEvent的作用就相当于一个拦截器,拦截住给自己使用。

好像忘了一个事情,就是dispatchTouchEvent如果返回false呢,会是一个什么结果呢,为什么再这个时候提这个问题呢,我们再来试试

再对viewgroup做出如下修改,运行查看log:

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("ssssssssssEvent","MyLinearLayout:dispatchTouchEvent");
//        return  super.dispatchTouchEvent(ev);
        return false;
    }

結果为什么和onInterceptTouchEvent好像,但是并没有执行onInterceptTouchEvent这个方法,因为当dispatchTouchEvent返回为false的时候,事件分发流程就会被当前的层给相应,因此onInterceptTouchEvent的作用也就失去了。所以dispatchTouchEvent的作用域要大于onInterceptTouchEvent的。

就剩下最后一个onTouchEvent方法了,这个方法就很面熟了,在我们日常写代码的时候用的也比较多了,其实这个方法中就是我们对一些触摸事件的处理,如果实在不知道可自行百度。

到这里我们也就结束了,是不是自己动手操作一遍发现原理其实就这么简单,原理是这样但是实际应用中其实摒弃掉其他东西也就是这么个事情,最后在总结一下:

什么是事件分发机制-将触摸事件(滑动,点击,长按不知道还有其他没)传递到某个View或者Viewgroup的这个过程

事件分发三个方法的介绍以及各自的作用

dispatchTouchEvent (activity,viewgroup,view都有的一个方法),判断此次行为是否被消费,一旦返回true那么剩下所有流程将都会停止,返回false的话,就会在当前层上相应行为,也不会向下传递,并且viewgroup中一旦返回false将不再执行onInterceptTouchEvent方法,此处需要注意

onInterceptTouchEvent(viewgroup中独有的方法),是否拦截行为,一旦返回true那么此次行为将有自己使用,不再向下传递

onTouchEvent(activity,viewgroup,view都有的一个方法),事件分发的具体实现了,到了这里就是你想用这个事件干什么了。

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值