网友通过本文主要向大家介绍了android事件分发机制,android事件传递机制,android事件处理机制,android事件机制,android 事件分发等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com
Android事件分发机制总结
理解事件的分发机制,需要对View和ViewGroup事件的分发分别探讨。View和ViewGroup的区别,一个View控件是指它里面不能再包含子控件了,常见的如TextView、Button、ImageView等,而ViewGroup是继承自View的,但是它里面可以包含一些子控件,包括View或者嵌套的ViewGroup,常用的大部分布局都是ViewGroup组件,如LinearLayout、RelativeLayout、FrameLayout等。
首先要明白的是,当我们触摸一个控件时(不论是View还是ViewGroup),都会调用dispatchTouchEvent()方法,开始事件的分发处理。我们先自定义一个简单的线性布局:
public class MyLinearLayout extends LinearLayout {
public MyLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
}
布局文件:
一、View事件的分发
运行后,我们点击Button控件,当事件传递到Button时会调用Button的dispatchTouchEvent方法(Button本身并没有dispatchTouchEvent方法,往上最终寻找到其父类View的dispatchTouchEvent方法)。根据dispatchTouchEvent源码来分析其处理流程:
public boolean dispatchTouchEvent(MotionEvent event) {
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) { //第一步
return true;
}
return onTouchEvent(event); //第二步
}
第一步:首先进行三个条件的判断:(1)查看是否给button设置了OnTouchListener()事件;
(2)控件是否Enable;(控件默认都是enable的)
(3)button里面实现的OnTouchListener监听里的onTuch()方法是否返回true;
如果条件都满足,则该事件被消耗掉,不再进入onTouchEvent中处理。
第二步:上述三个条件不同时满足时,事件将交给onTouchEvent方法处理。再根据onTouchEvent源码分析其处理流程:
public boolean onTouchEvent(MotionEvent event) {
final int viewFlags = mViewFlags;
if ((viewFlags & ENABLED_MASK) == DISABLED) {
// A disabled view that is clickable still consumes the touch
// events, it just doesn't respond to them.
return (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));
}
if (mTouchDelegate != null) {
if (mTouchDelegate.onTouchEvent(event)) {
return true;
}
}
if (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {//第一点
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
boolean prepressed = (mPrivateFlags & PREPRESSED) != 0;
if ((mPrivateFlags & PRESSED) != 0 || prepressed) {
// take focus if we don't have it already and we should in
// touch mode.
boolean focusTaken = false;
if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
focusTaken = requestFocus();
}
if (!mHasPerformedLongPress) {
// This is a tap, so remove the longpress check
removeLongPressCallback();
// Only perform take click actions if we were in the pressed state
if (!focusTaken) {
// Use a Runnable and post this rather than calling
// performClick directly. This lets other visual state
// of the view update before click actions start.
if (mPerformClick == null) {
mPerformClick = new PerformClick();
}
if (!post(mPerformClick)) {
performClick(); //第二点
}
}
}
if (mUnsetPressedState == null) {
mUnsetPressedState = new UnsetPressedState();
}
if (prepressed) {
mPrivateFlags |= PRESSED;
refreshDrawableState();
postDelayed(mUnsetPressedState,
ViewConfiguration.getPressedStateDuration());
} else if (!post(mUnsetPressedState)) {
// If the post failed, unpress right now
mUnsetPressedState.run();
}
removeTapCallback();
}
break;
case MotionEvent.ACTION_DOWN:
if (mPendingCheckForTap == null) {
mPendingCheckForTap = new CheckForTap();
}
mPrivateFlags |= PREPRESSED;
mHasPerformedLongPress = false;
postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
break;
case MotionEvent.ACTION_CANCEL:
mPrivateFlags &= ~PRESSED;
refreshDrawableState();
removeTapCallback();
break;
case MotionEvent.ACTION_MOVE:
final int x = (int) event.getX();
final int y = (int) event.getY();
// Be lenient about moving outside of buttons
int slop = mTouchSlop;
if ((x < 0 - slop) || (x >= getWidth() + slop) ||
(y < 0 - slop) || (y >= getHeight() + slop)) {
// Outside button
removeTapCallback();
if ((mPrivateFlags & PRESSED) != 0) {
// Remove any future long press/tap checks
removeLongPressCallback();
// Need to switch from pressed to not pressed
mPrivateFlags &= ~PRESSED;
refreshDrawableState();
}
}
break;
}
return true;
}
return false;
}
源码很长,我们只需关注重要的几点即可。
第一点:这里有一个长长的if语句
if (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE))
用于判断该View是否是可点击的或是否可长按的View,明显我们的Button属于可点击的View控件。进入到if里面后转入到switch中,当执行完switch语句后,直接执行
return true;呵呵,说明什么?只要是该控件是可点击的或者可长按的View,这个事件就会被消耗掉!这也符合我们的认知,按钮Button之类的不就是让人来点击处理的么,但是对于那些TextView、ImageView之类的非可点击控件,我们平常不是也能够处理点击事件吗?回忆一下,我们在处理这些点击事件的时候,一定通过setOnClickListener()给它设置了点击监听OnClickListener(或者在布局中声明了android:clickable="true"),setOnClickListener源码如下:
public void setOnClickListener (OnClickListener l) {
if (!isClickable()) {
setClickable( true);
}
mOnClickListener = l;
}
可知,设置了

