Window,LayoutParams,View及事件分发

什么是窗口(Window)? 

Window界面显示的最顶级元素, 任何东西都是显示在Window上的, 包括Activity, 对话框, Toast, 状态栏. 可以对比Windows里窗口, 有的手机也有多窗口功能。

Window是一个抽象类,是所有视图的最顶层容器,视图的外观和行为都归他管,不论是背景显示,标题栏还是事件处理都是他管理的范畴。
PhoneWindow是Window的唯一实现类。
DecorView是PhoneWindow的一个内部类,PhoneWindow的指示通过DecorView传递给下面的 View,而下面 View 的信息也通过 DecorView回传给PhoneWindow。

LayoutParams 表示布局参数, 封装了一些被添加的Window的参数, 或者说是特征。

什么是LayoutParams? 
1、布局参数, 封装了一个View的布局信息以及一些属性/特征.
2、在布局文件里, 如果一个属性以 layout_ 开头, 这些属性的值会被封装到 LayoutParams 里
3、所有在布局文件里配置的属性, 都可以使用代码设置值, 对于不带 layout_ 的属性, 可以调用某些setXxx方法设置,对于带 layout_ 的属性, 就要使用 LayoutParams 设置, setLayoutParams 方法
4、以 layout_ 开头的属性, 都是子View自己决定不了的, 要和父View商量
5、 每个ViewGroup都有一个内部类 LayoutParams, 定义了一些只有它的子View才能有的属性

要处理一个View的触摸事件, 可以重写它的onTouchEvent方法, 也可以给它设置OnTouchListener, 重写OnTouchListener中的onTouch方法

// 当View被触摸的时候, OnTouchListener中的 onTouch 方法会被调用
// MotionEvent 封装了整个事件
// 返回值表示要不要处理当前触摸事件
// 事件的动作: 一个DOWN - n个 MOVE - 一个UP
private int mStartX;
private int mStartY;
@Override
public boolean onTouch(View v, MotionEvent event) {
	switch (event.getAction()) {
	case MotionEvent.ACTION_DOWN:
		// 一律使用int值, 否则移动时会发生偏移,getRawX()距离屏幕的距离
		mStartX = (int) event.getRawX();
		mStartY = (int) event.getRawY();
		break;
	case MotionEvent.ACTION_MOVE:
		break;
	case MotionEvent.ACTION_UP:
		break;
	default:
		break;
	}
	return true; // 表示要处理这个触摸事件
}

事件分发:

Activity:dispatchTouchEvent(事件分发)有、onInterceptTouchEvent(事件拦截)无、onTouchEvent(事件消费)有。

View:dispatchTouchEvent(事件分发)有、onInterceptTouchEvent(事件拦截)无、onTouchEvent(事件消费)有。
ViewGroup:dispatchTouchEvent(事件分发)有、onInterceptTouchEvent(事件拦截)有、onTouchEvent(事件消费)有。

事件传递流程
Activity <-> PhoneWindow <-> DecorView <-> ViewGroup <-> ... <-> View
ViewGroup 的事件分发机制伪代码如下,可以看出调用的顺序。
public boolean dispatchTouchEvent(MotionEvent ev) {
	boolean result = false;// 默认状态为没有消费过
	if (!onInterceptTouchEvent(ev)) {// 如果没有拦截交给子View
		result = child.dispatchTouchEvent(ev);
	}
	if (!result) {// 如果事件没有被消费,询问自身onTouchEvent
		result = onTouchEvent(ev);
	}
	return result;
}
记住以下几条原则:
1.如果事件被消费,就意味着事件信息传递终止。
2.如果事件一直没有被消费,最后会传给Activity,如果Activity也不需要就被抛弃。
3.判断事件是否被消费是根据返回值,true 表示消费,false 表示不消费,而不是根据你是否使用了事件。
4. 不论 View 自身是否注册点击事件,只要 View 是可点击的就会消费事件。
5.View 只有消费了 ACTION_DOWN 事件,才能接收到后续的事件(可点击控件会默认消费所有事件),并且会将后续所有事件传递过来,不会再传递给其他 View,除非上层 View 进行了拦截。
6.View 的 dispatchTouchEvent 主要用于调度自身的监听器和 onTouchEvent。
7.View的事件的调度顺序是 onTouchListener > onTouchEvent > onLongClickListener > onClickListener 。
8.不论 View 自身是否注册点击事件,只要 View 是可点击的就会消费事件。
9.ViewGroup 中可能有多个 ChildView 时,将事件分配给包含点击位置的 ChildView。
10.ViewGroup 和 ChildView 同时注册了事件监听器(onClick等),由 ChildView 消费。
11.一次触摸流程中产生事件应被同一 View 消费,全部接收或者全部拒绝。
12.只要接受 ACTION_DOWN 就意味着接受所有的事件,拒绝 ACTION_DOWN 则不会收到后续内容。
13.如果当前正在处理的事件被上层 View 拦截,会收到一个 ACTION_CANCEL,后续事件不会再传递过来。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值