Android的Touch事件分发机制,看完这个就够了


最近在整理 关于Android的Touch事件的分发机制,首先Touch事件的方法包括三种:dispatchTouchEvent(MotionEvent event) , onInterceptTouchEvent(MotionEvent ev) , onTouchEvent(MotionEvent event) ,下面是这三个方法在界面中的调用映射表:

Touch事件的方法方法介绍ViewViewGroupActivity
dispatchTouchEvent事件的分发yesyesyes
onInterceptTouchEvent事件的拦截yesyesno
onTouchEvent事件的响应yesyesyes

Ps:这里的View 若只是Button或者其他不包含子控件的View是不包含OnInterceptTouchEvent方法的。
下面进行事件分发的详细解析:

Touch事件的方法\返回值解析truefalsesuper()
dispatchTouchEvent每次的Touch都会由Activity的dispatchTouchEvent向下层的View或ViewGroup进行事件分发☞当前的控件自己处理事件1、若该View是Activity或者是button等不含子控件的View,则将事件分发给自己处理 ☞ ; 2、否则传递给上层的Activity或者父控件的OnTouchEvent方法 ☝☟ 下发给Activity的子控件或View自身的OnIntercepterTouchEvent
onInterceptTouchEvent是否拦截事件☞ 当前View的OnTouchEvent☟ 子控件的dispatch
onTouchEvent事件的响应☞ 当前View☝ 父控件的TouchEvent

解释:

☝ : 表示向上父类传递事件
☟ : 表示向下子类分发事件
☞ : 表示由自己来处理事件
下面 我们通过代码来验证一下我们上面的理论:
首先定义两个子布局:
tauchButton:

public class tauchButton extends LinearLayout {
    public tauchButton(Context context) {
        super(context);
    }

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

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

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.i("zgy", "TouchEventChilds | onTouchEvent --> " + TouchEventUtil.getTouchAction(event.getAction()));
        return super.onTouchEvent(event);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.i("zgy", "TouchEventChilds | dispatchTouchEvent --> " + TouchEventUtil.getTouchAction(event.getAction()));
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.i("zgy", "TouchEventChilds | onInterceptTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));
        return super.onInterceptTouchEvent(ev);
    }

}

父控件touchLinearlayout:

public class touchLinearlayout extends LinearLayout {
    public touchLinearlayout(Context context) {
        super(context);
    }

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

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


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("zgy", "TouchEventFather | onTouchEvent --> " + TouchEventUtil.getTouchAction(event.getAction()));
        return super.onTouchEvent(event);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("zgy", "TouchEventFather | dispatchTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        Log.e("zgy", "TouchEventFather | onInterceptTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));
        return super.onInterceptTouchEvent(ev);
    }

}

activity的layout布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.example.lk.helloworld.view.touchLinearlayout
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:background="@color/bg_discount"
        android:layout_gravity="center">

        <com.example.lk.helloworld.view.tauchButton
            android:id="@+id/buttonChild"
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:text="button"
            android:background="@color/bg_blue_light"
            android:layout_gravity="center"
            android:layout_marginLeft="20dp"
            />
    </com.example.lk.helloworld.view.touchLinearlayout>

</LinearLayout>

Activity1:

package com.example.lk.helloworld;

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

import com.example.lk.helloworld.utils.TouchEventUtil;

/**
 *
 */
public class Activity1 extends Activity {

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

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.w("zgy", "TouchEventActivity | onTouchEvent --> " + TouchEventUtil.getTouchAction(event.getAction()));
        return super.onTouchEvent(event);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.w("zgy", "TouchEventActivity | dispatchTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));
        return super.dispatchTouchEvent(ev);
    }
}

首先我们先看看都使用super的方法时是神马结果;
case1 : 所有的返回值都调用super方法
结果演示
这里我们可以看出,首先由Activity的dispatchTouchEvent方法,想下分发事件,由于是Activity,没有OnIterceptTouchEvent因此是分发给子控件的dispatchTouchEvent方法,当到TouchEventFather分发事件的时候,就是分发给了自己的OnIntercepterTouchEvent ; 这时候调用的依然是super的方法,根据上面的表格显示,默认不拦截,就把事件分发给了下一个控件的dispatchTouchEvent , 最终由于都没有消耗该事件,于是事件会由子控件返回给当前的Acticity,然后释放掉。
下面我们随机测试一下其他的情况:
case2 : 父控件的onTouchEvent的返回值设置为true
这里写图片描述
截图可以看出,当运行到TouchEventFather的OnTouchEvent的时候,就把事件给消耗掉了,就不会走Activity的OntouchEvent的方法了;
case3:tauchButton的dispatchTouchEvent的返回值是false
这里写图片描述
截图可以发现,当运行到tauchButton的dispatchEvent方法,返回false时,事件不再向下分发,而是将事件传递给上层的View的OntouchEvent方法;
剩下的 都经过实践的出,这里不再一一列举。
当然到这里,我们基本搞懂了View的事件分发,不过我们似乎还忘了一点事情,那就是View的监听事件:setOnTouchListener 和 setOnClickListener.到这里的时候 我突然想到如果给button加一个监听事件会怎么样。
下面将Activity该成如下形式:

package com.example.lk.helloworld;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import com.example.lk.helloworld.utils.TouchEventUtil;
import com.example.lk.helloworld.view.tauchButton;

/**
 *
 */
public class Activity1 extends Activity {

    private tauchButton buttonChild;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity1_layout);

        buttonChild = (tauchButton)findViewById(R.id.buttonChild);
        buttonChild.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.e("Activity1.this","touchListener 事件触发");
                return true;
            }
        });
        buttonChild.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.e("Activity1.this", "clickListener 事件触发");
            }
        });
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.w("zgy", "TouchEventActivity | onTouchEvent --> " + TouchEventUtil.getTouchAction(event.getAction()));
        return super.onTouchEvent(event);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.w("zgy", "TouchEventActivity | dispatchTouchEvent --> " + TouchEventUtil.getTouchAction(ev.getAction()));
        return super.dispatchTouchEvent(ev);
    }
}

这里写图片描述
我们再次运行会发现如图所示。当事件分发到TouchEventChilds的OntouchEvent的时候,被touchListener事件拦截,并且消耗掉事件。
如果我们把setOnTouchListener的返回值设置为false;
这里写图片描述
这时我们可以发现,事件会被一直传递下去,直到传递给setOnClickListener事件。如果没有监听Onclick事件的时候:
这里写图片描述
事件会按原路返回到Activity然后释放掉;
那么我们现在可以发现:
触摸事件传递顺序:dispatchTouchEvent–>>onTouch–>>onTouchEvent–>>onClick。而且是当OnTouchEvent的手势ACTION_UP结束的时候才会调用Onclick方法。到这里我们基本对Touch的事件有了一定的了解了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值