网友通过本文主要向大家介绍了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; }可知,设置了