android view 事件分发笔记
来源:互联网 发布:pcb仿真软件 编辑:程序博客网 时间:2024/05/12 21:45
对于Button :
button.setOnTouchListener(new OnTouchListener() {@Overridepublic boolean onTouch(View arg0, MotionEvent arg1) {// TODO Auto-generated method stubSystem.out.println("button onTouch");return true;}});
button.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View arg0) {// TODO Auto-generated method stubSystem.out.println("button onClick");}});
当Button注册onTouch()事件,并且返回true时,点击Button时会打印两个Button onTouch,并且屏蔽掉onClick()事件。因此不会打印“Button onClick"。其中,打印两次”Button onTouch"是因为
public boolean dispatchTouchEvent(MotionEvent event) { if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && mOnTouchListener.onTouch(this, event)) { return true; } return onTouchEvent(event);}
这个方法非常的简洁,只有短短几行代码!我们可以看到,在这个方法内,首先是进行了一个判断,如果mOnTouchListener != null,(mViewFlags & ENABLED_MASK) == ENABLED和mOnTouchListener.onTouch(this, event)这三个条件都为真,就返回true,否则就去执行onTouchEvent(event)方法并返回。
先看一下第一个条件,mOnTouchListener这个变量是在哪里赋值的呢?我们寻找之后在View里发现了如下方法:
public void setOnTouchListener(OnTouchListener l) { mOnTouchListener = l;}1)mOnTouchListener正是在setOnTouchListener方法里赋值的,也就是说只要我们给控件注册了touch事件,mOnTouchListener就一定被赋值了。
2)第二个条件(mViewFlags & ENABLED_MASK) == ENABLED是判断当前点击的控件是否是enable的,按钮默认都是enable的,因此这个条件恒定为true。
3)第三个条件就比较关键了,mOnTouchListener.onTouch(this, event),其实也就是去回调控件注册touch事件时的onTouch方法。也就是说如果我们在onTouch方法里返回true,就会让这三个条件全部成立,从而整个方法直接返回true。如果我们在onTouch方法里返回false,就会再去执行onTouchEvent(event)方法。
因此,当Button的OnTouch()事件返回true时,则不会执行onTouchEvent()方法,由于前一个动作返回true,那么事件分发方法则会继续执行点击事件,因此会打印两个“Button onTouch",其中一个是响应down事件的,另一个是响应up事件。此根据借鉴于(touch事件的层级传递。我们都知道如果给一个控件注册了touch事件,每次点击它的时候都会触发一系列的ACTION_DOWN,ACTION_MOVE,ACTION_UP等事件。这里需要注意,如果你在执行ACTION_DOWN的时候返回了false,后面一系列其它的action就不会再得到执行了。简单的说,就是当dispatchTouchEvent在进行事件分发的时候,只有前一个action返回true,才会触发后一个action。)
二.当Button的onTouch事件返回false时,则会打印两次"Button onTouch",而且会执行OnClick()方法,打印"Button OnClick".
1)打印两次"Button OnTouch"的原因:onTouch()方法返回false,那么dispatchTouchEvent()里面则会执行onTouchEvent()事件,在ouTouchEvent()方法里面,由于Button是默认可以点击的,所以,根据源码:
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()方法里面,因此,不管是down,up,还是move动作都会放回true,根据前面说的,要想继续执行下一个动作,那么前一个动作一定要返回true,即dispatchTouchEvent()返回true,才能继续执行下一个动作,例如up动作,由于Button在View里dispatchTouchEvent()都是返回true的,所以,不论Button的onTouch()事件是返回true,还是false,它都会执行打印两次“Butt onTouch".
2)而至于打印”Button onClick"的原因是:执行了OnTouchEvent()方法,而OnClick()方法是在动作up之后执行的,所以会打印“Button OnClick".
- android view 事件分发笔记
- Android View事件分发机制学习笔记
- Android View的事件分发机制笔记
- android 事件分发 View
- android View 事件分发
- android view 事件分发
- Android View事件分发
- android View事件分发
- android View 事件分发
- Android View 事件分发
- android view事件分发
- 【Android学习笔记】Android中View的事件分发机制
- view事件分发机制笔记
- Android进阶笔记(一)View事件分发机制理解
- Android学习笔记——View事件分发(上)
- Android 学习笔记之四 View的事件分发机制
- Android学习笔记 3.4View的事件分发机制
- Android 开发艺术探索笔记-View的事件分发
- Resize images and save thumbnails
- Android View与LayoutInflater
- Linux command line install Oracle Java
- Ugly Number
- Hadoop安装教程_单机/伪分布式配置
- android view 事件分发笔记
- C的内存管理
- Unity开发Android游戏(二)Hello world!
- Pro Git中文版——起步
- 性能调优攻略
- UILabel的一些不常用属性,持续更新
- Android中的类装载器DexClassLoader
- spring的annotation-driven配置事务管理器详解
- oracle定义job执行存储过程方式