Activity的事件分发机制

MotionEvent的4种类型

事件类型 具体动作
MotionEvent.ACTION_DOWN 按下(所有事件的开始)
MotionEvent.ACTION_UP 抬起
MotionEvent.ACTION_MOVE 滑动
MotionEvent.ACTION_CANCEL 结束事件(非人为原因)

事件分发的本质是将点击事件(MotionEvent)传递到某个具体的View & 处理的整个过程。

事件传递会经过 Activity -> ViewGroup -> View 三个对象。

Activity的事件分发机制

当一个点击事件发生时,事件最先传到Activity的dispatchTouchEvent()进行事件分发

dispatchTouchEvent源码分析

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback, WindowControllerCallback,
        AutofillManager.AutofillClient {
        
    ......
        
    public boolean dispatchTouchEvent(MotionEvent ev) {

        // 一般事件列开始都是 DOWN 事件,故此处基本是true
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            onUserInteraction(); 
         }
		// 若getWindow().superDispatchTouchEvent(ev)的返回true
		// 则Activity.dispatchTouchEvent()就返回true,则方法结束。即 :该点击事件停止往下传递 & 事件传递过程结束
        // 否则:继续往下调用Activity.onTouchEvent
        if (getWindow().superDispatchTouchEvent(ev)) {      		
            return true;
        }
        return onTouchEvent(ev);
        
    }
    /**
  	 * 作用:实现屏保功能
  	 * a. 该方法为空方法
  	 * b. 当此activity在栈顶时,触屏点击按home,back,menu键等都会触发此方法
  	 */

    public void onUserInteraction() {
    
    }

  	public boolean onTouchEvent(MotionEvent event) {

        // 当一个点击事件未被Activity下任何一个View接收处理时
        // 应用场景:处理发生在Window边界外的触摸事件    
        if (mWindow.shouldCloseOnTouch(this, event)) {
            finish();
            return true;
        }
        // 即 只有在点击事件在Window边界外才会返回true,一般情况都返回false,分析完毕
        return false;
        	
   	}
    ......
}

getWindow().superDispatchTouchEvent(ev)

Window类是抽象类,其唯一实现类是PhoneWindow类;即此处的Window类对象 就是PhoneWindow类对象

public class PhoneWindow extends Window implements MenuBuilder.Callback {

	......
	@Override
    public boolean superDispatchTouchEvent(MotionEvent event) {
    	//mDecor = 顶层View(DecorView)的实例对象
        return mDecor.superDispatchTouchEvent(event);
    }
    
    //mWindow.shouldCloseOnTouch(this, event)事件
    public boolean shouldCloseOnTouch(Context context, MotionEvent event) {
    // 主要是对于处理边界外点击事件的判断:是否是 DOWN 事件,event的坐标是否在边界内等
    if (mCloseOnTouchOutside && event.getAction() == MotionEvent.ACTION_DOWN
            && isOutOfBounds(context, event) && peekDecorView() != null) {
        return true;
    }
    ......
    
}

DecorView类是PhoneWindow类的一个内部类,DecorView继承自FrameLayout,是所有界面的父类,FrameLayout是ViewGroup的子类,故DecorView的间接父类ViewGroup

DecorView的superDispatchTouchEvent

public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks
	......
    public boolean superDispatchTouchEvent(MotionEvent event) {
		//调用父类的方法 = ViewGroup的dispatchTouchEvent()
        //即将事件传递到ViewGroup去处理,详细请看ViewGroup的事件分发机制
        return super.dispatchTouchEvent(event);
    }
    ......
}

事件的分发是:
由Activity的dispatchTouchEvnent方法开始
–>>然后调用PhoneWindow的superDispatchTouchEvent方法
–>>接着调用DecorView的superDispatchTouchEvent方法
–>>最后还是调用ViewGroup的dispatchTouchEvent方法

具体流程如下图所示
在这里插入图片描述

发布了206 篇原创文章 · 获赞 68 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/u013728021/article/details/102826314
今日推荐