彻底了解android view 事件机制中的“隧道”和“冒泡”

本文详细探讨了Android View事件分发机制,通过实验揭示了ACTION_DOWN事件的“隧道”传递和“冒泡”过程。在三层View结构中,ACTION_DOWN先向下传递至最底层LeafView,然后回溯到顶层TestViewEventActivity,形成隧道和冒泡。ACTION_MOVE和ACTION_UP事件在未被消耗时直接由TestViewEventActivity处理。当ACTION_DOWN被某个View消耗(onTouchEvent返回true),后续事件交由该View处理。onInterceptTouchEvent可以中断隧道过程,提前启动冒泡。总结了事件分发规律和onInterceptTouchEvent的作用。
摘要由CSDN通过智能技术生成

android view事件传递机制对不管是初学者还是有经验的开发者来说,都是一个比较核心的机制。可能说起事件分发机制,很多人都能立马就能说出dispatchTouchEvent(),onInterceptTouchEvent(),onTouchEvent()这三个回调方法,有些人甚至可能也会说出“隧道“,“冒泡“机制。诚然,android 的view事件分发机制确实离不开这三个方法,但是对于这三个方法之间是如何分发,拦截,相互协调工作的,怎样“隧道“,“冒泡“以及每个方法中返回的布尔值对触摸事件造成的影响,相信很多人理解的可能还不是十分透彻。

本篇文章就将通过在一个三层的view型树结构上触发手势触摸事件实验,通过不断修改这三个方法中的返回值,来深入理解android 中 view的事件分发,拦截机制。

该实验中将用到四个类文件,分别是:

  • TestViewEventActivity :用来展示三层view布局文件,以及接收用户触摸事件的Activity
  • OuterLayout 第一层,继承自RelativeLayout
  • InngerLayout 第二层view,继承自RelativeLayout
  • LeafView 第三层view ,继承子TextView

    运行起来后,效果图展示如下:

这里写图片描述

先来看TestViewEventActivity的源代码:

package love.gaoge.view.event;

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

import love.gaoge.R;
import love.gaoge.base.BaseActivity;
import love.gaoge.util.Logg;

/**
 * 测试父view,子view touch事件
 * @author gaoge
 * @version V1.0
 * @date 2016-03-02 18:20
 * @tips
 */
public class TestViewEventActivity extends BaseActivity{
   

    String tag = "eve";

    private OuterLayout outer;
    private InnerLayout inner;
    private LeafView leaf;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.test_view_event);

        outer = (OuterLayout)findViewById(R.id.outer);
        inner = (InnerLayout)findViewById(R.id.inner);
        leaf = (LeafView)findViewById(R.id.leaf);

        /**
         * 只有设置了clickListener以后,才可以监听到ACTION_MOVE,ACTION_UP事件!!!
         */
//        outer.setOnClickListener(this);
//        inner.setOnClickListener(this);
//        leaf.setOnClickListener(this);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                Logg.d(tag, "TestViewEvent.dispatchTouchEvent(),ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Logg.d(tag, "TestViewEvent.dispatchTouchEvent(),ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Logg.d(tag, "TestViewEvent.dispatchTouchEvent(),ACTION_UP");
                break;
            case MotionEvent.ACTION_CANCEL:
                Logg.d(tag, "TestViewEvent.dispatchTouchEvent(),ACTION_CANCEL");
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                Logg.d(tag, "TestViewEvent.onTouchEvent(),ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Logg.d(tag, "TestViewEvent.onTouchEvent(),ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Logg.d(tag, "TestViewEvent.onTouchEvent(),ACTION_UP");
                break;
            case MotionEvent.ACTION_CANCEL:
                Logg.d(tag, "TestViewEvent.onTouchEvent(),ACTION_CANCEL");
                break;
        }

        return super.onTouchEvent(event);
    }
}

OuterLayout源代码:

package love.gaoge.view.event;

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

import love.gaoge.util.Logg;

/**
 * @author gaoge
 * @version V1.0
 * @date 2016-03-02 18:18
 * @tips
 */
public class OuterLayout extends RelativeLayout {
   

    String tag = "eve";

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

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

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                Logg.d(tag, "OuterLayout.dispatchTouchEvent(),ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Logg.d(tag, "OuterLayout.dispatchTouchEvent(),ACTION_MOVE");
                break;
            case MotionEvent.ACTION_UP:
                Logg.d(tag, 
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值