2015-11-26 17:00:22
前言:Android的Touch事件传递和View的实现紧密相连,因此理解Touch事件的传递,有助于我们更好的理解View的工作原理。
1. 几个重要的方法:
View.java
=============
dispatchTouchEvent():用来分发、传递Touch事件,如果Touch事件被当前View处理了,就返回true,否则返回false。
1 /** 2 * Pass the touch screen motion event down to the target view, or this 3 * view if it is the target. 4 * 将Touch事件传递到目标View,如果自己就是目标View的话,就给自己 5 * @param event The motion event to be dispatched. 6 * @return True if the event was handled by the view, false otherwise. 7 */ 8 public boolean dispatchTouchEvent(MotionEvent event) { 9 // If the event should be handled by accessibility focus first. 10 if (event.isTargetAccessibilityFocus()) { 11 // We don't have focus or no virtual descendant has it, do not handle the event. 12 if (!isAccessibilityFocusedViewOrHost()) { 13 return false; 14 } 15 // We have focus and got the event, then use normal event dispatch. 16 event.setTargetAccessibilityFocus(false); 17 } 18 19 boolean result = false; 20 21 if (mInputEventConsistencyVerifier != null) { 22 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 23 } 24 25 final int actionMasked = event.getActionMasked(); 26 if (actionMasked == MotionEvent.ACTION_DOWN) { 27 // Defensive cleanup for new gesture 28 stopNestedScroll(); 29 } 30 31 if (onFilterTouchEventForSecurity(event)) { 32 //noinspection SimplifiableIfStatement 33 ListenerInfo li = mListenerInfo; 34 if (li != null && li.mOnTouchListener != null 35 && (mViewFlags & ENABLED_MASK) == ENABLED 36 && li.mOnTouchListener.onTouch(this, event)) { (1) 37 result = true; 38 } 39 40 if (!result && onTouchEvent(event)) { (2) 41 result = true; 42 } 43 } 44 45 if (!result && mInputEventConsistencyVerifier != null) { 46 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 47 } 48 49 // Clean up after nested scrolls if this is the end of a gesture; 50 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 51 // of the gesture. 52 if (actionMasked == MotionEvent.ACTION_UP || 53 actionMasked == MotionEvent.ACTION_CANCEL || 54 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 55 stopNestedScroll(); 56 } 57 58 return result; 59 }
通俗理解:
该方法是View上Touch事件传递的第一道防线,现在只需要记住:
(1)处代码调用了OnTouchListener,如果你给当前View设置了setOnTouchListener(),那么,此处会被调用;
(2)如果你设置的onTouchListener的onTouch方法,返回的是false,那么此处有机会调用当前View的onTouchEvent方法。如果返回true,不会调用onTouchEvent,同时你设置的onClickListener也不会得到调用,这点我们接下来分析。
onTouchEvent():当前View收到Touch事件后,真正使用Touch事件的地方。
1 public boolean onTouchEvent(MotionEvent event) { 2 final float x = event.getX(); 3 final float y = event.getY(); 4 final int viewFlags = mViewFlags; 5 6 if ((viewFlags & ENABLED_MASK) == DISABLED) { 7 if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 8 setPressed(false); 9 } 10 // A disabled view that is clickable still consumes the touch 11 // events, it just doesn't respond to them. 12 return (((viewFlags & CLICKABLE) == CLICKABLE || 13 (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)); 14 } 15 16 if (mTouchDelegate != null) { 17 if (mTouchDelegate.onTouchEvent(event)) { 18 return true; 19 } 20 } 21 22 if (((viewFlags & CLICKABLE) == CLICKABLE || 23 (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) { 24 switch (event.getAction()) { 25 case MotionEvent.ACTION_UP: 26 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 27 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 28 // take focus if we don't have it already and we should in 29 // touch mode. 30 boolean focusTaken = false; 31 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 32 focusTaken = requestFocus(); 33 } 34 35 if (prepressed) { 36 // The button is being released before we actually 37 // showed it as pressed. Make it show the pressed 38 // state now (before scheduling the click) to ensure 39 // the user sees it. 40 setPressed(true, x, y); 41 } 42 43 if (!mHasPerformedLongPress) { 44 // This is a tap, so remove the longpress check 45 removeLongPressCallback(); 46 47 // Only perform take click actions if we were in the pressed state 48 if (!focusTaken) { 49 // Use a Runnable and post this rather than calling 50 // performClick directly. This lets other visual state 51 // of the view update before click actions start. 52 if (mPerformClick == null) { 53 mPerformClick = new PerformClick(); 54 } 55 if (!post(mPerformClick)) { 56 performClick(); (1) 57 } 58 } 59 } 60 61 if (mUnsetPressedState == null) { 62 mUnsetPressedState = new UnsetPressedState(); 63 } 64 65 if (prepressed) { 66 postDelayed(mUnsetPressedState, 67 ViewConfiguration.getPressedStateDuration()); 68 } else if (!post(mUnsetPressedState)) { 69 // If the post failed, unpress right now 70 mUnsetPressedState.run(); 71 } 72 73 removeTapCallback(); 74 } 75 break; 76 77 case MotionEvent.ACTION_DOWN: 78 mHasPerformedLongPress = false; 79 80 if (performButtonActionOnTouchDown(event)) { 81 break; 82 } 83 84 // Walk up the hierarchy to determine if we're inside a scrolling container. 85 boolean isInScrollingContainer = isInScrollingContainer(); 86 87 // For views inside a scrolling container, delay the pressed feedback for 88 // a short period in case this is a scroll. 89 if (isInScrollingContainer) { 90 mPrivateFlags |= PFLAG_PREPRESSED; 91 if (mPendingCheckForTap == null) { 92 mPendingCheckForTap = new CheckForTap(); 93 } 94 mPendingCheckForTap.x = event.getX(); 95 mPendingCheckForTap.y = event.getY(); 96 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 97 } else { 98 // Not inside a scrolling container, so show the feedback right away 99 setPressed(true, x, y); 100 checkForLongClick(0); (2) 101 } 102 break; 103 104 case MotionEvent.ACTION_CANCEL: 105 setPressed(false); 106 removeTapCallback(); 107 removeLongPressCallback(); 108 break; 109 110 case MotionEvent.ACTION_MOVE: 111 drawableHotspotChanged(x, y); 112 113 // Be lenient about moving outside of buttons 114 if (!pointInView(x, y, mTouchSlop)) { 115 // Outside button 116 removeTapCallback(); 117 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 118 // Remove any future long press/tap checks 119 removeLongPressCallback(); 120 121 setPressed(false); 122 } 123 } 124 break; 125 } 126 127 return true; 128 } 129 130 return false; 131 }
在onTouchEvent()方法中,分别处理不同类型的Touch事件。注意:
(1)当前View处理Click事件的地方,没错,就是在MotionEvent.Action_UP的时候处理的;
(2)当前View处理LongClick事件的地方,在MotionEvent.Action_DOWN的时候处理的;
ViewGroup.java
=============
ViewGroup是继承自View的,当然也继承了上面那两个方法。ViewGroup不仅是一个View,也是一个可以拥有Children View的View Container,所以它重写了dispatchTouchEvent()方法,但是没有重写onTouchEvent()方法。同时,ViewGroup觉得自己好歹是个Container,得有点特权嘛,所以给自己搞了个onInterceptTouchEvent()方法,如下:
1 public boolean dispatchTouchEvent(MotionEvent ev) { 2 3 boolean handled = false; 4 if (onFilterTouchEventForSecurity(ev)) { 5 final int action = ev.getAction(); 6 final int actionMasked = action & MotionEvent.ACTION_MASK; 7 8 // Handle an initial down. 9 if (actionMasked == MotionEvent.ACTION_DOWN) { 10 // Throw away all previous state when starting a new touch gesture. 11 // The framework may have dropped the up or cancel event for the previous gesture 12 // due to an app switch, ANR, or some other state change. 13 cancelAndClearTouchTargets(ev); 14 resetTouchState(); 15 } 16 17 // Check for interception. 18 final boolean intercepted; 19 if (actionMasked == MotionEvent.ACTION_DOWN 20 || mFirstTouchTarget != null) { 21 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0; 22 if (!disallowIntercept) { 23 intercepted = onInterceptTouchEvent(ev); (1) 24 ev.setAction(action); // restore action in case it was changed 25 } else { 26 intercepted = false; 27 } 28 } else { 29 // There are no touch targets and this action is not an initial down 30 // so this view group continues to intercept touches. 31 intercepted = true; 32 } 33 34 // Check for cancelation. 35 final boolean canceled = resetCancelNextUpFlag(this) 36 || actionMasked == MotionEvent.ACTION_CANCEL; 37 38 // Update list of touch targets for pointer down, if needed. 39 final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0; 40 TouchTarget newTouchTarget = null; 41 boolean alreadyDispatchedToNewTouchTarget = false; 42 if (!canceled && !intercepted) { (2) 43 …… 44 45 }
ViewGroup的dispatchTouchView()方法,加了一些自己的判断,最终调用的仍然是View中的dispatchTouchView(),先关注一下红色代码:
(1)ViewGroup调用了自己的onInterceptTouchEvent();
(2)只有onInterceptTouchEvent()返回false时,才会继续执行下面的代码。这里可以这么理解,onInterceptTouchEvent()返回true,表示该Touch事件被拦截,不会向Children View传递,分发给自己handle,如果返回false,才会继续向Children View传递。
onInterceptTouchEvent(MotionEvent ev):
1 /* @param ev The motion event being dispatched down the hierarchy. 2 * @return Return true to steal motion events from the children and have 3 * them dispatched to this ViewGroup through onTouchEvent(). 4 * The current target will receive an ACTION_CANCEL event, and no further 5 * messages will be delivered here. 6 */ 7 public boolean onInterceptTouchEvent(MotionEvent ev) { 8 return false; 9 }
此方法默认返回false。
2. 写个小Demo,源码如下:
MyLinear1.java
1 public class MyLinear1 extends LinearLayout { 2 public MyLinear1(Context context) { 3 super(context); 4 } 5 6 public MyLinear1(Context context, AttributeSet attrs) { 7 super(context, attrs); 8 } 9 10 public MyLinear1(Context context, AttributeSet attrs, int defStyleAttr) { 11 super(context, attrs, defStyleAttr); 12 } 13 14 @Override 15 protected void onLayout(boolean changed, int l, int t, int r, int b) { 16 super.onLayout(changed, l, t, r, b); 17 } 18 19 boolean isDispatch = true; 20 21 @Override 22 public boolean dispatchTouchEvent(MotionEvent ev) { 23 Log.e("David--MyLinear", "dispatchTouchEvent-" + getS(ev.getAction())); 24 if (isDispatch) { 25 boolean one = super.dispatchTouchEvent(ev); 26 Log.e("David--MyLinear", "dispatchTouchEvent() super.dispatchTouchEvent(event) = " + one); 27 return one; 28 } else { 29 return true; 30 } 31 } 32 33 @Override 34 public boolean onTouchEvent(MotionEvent event) { 35 Log.e("David--MyLinear", "onTouchEvent-" + getS(event.getAction())); 36 return true; 37 } 38 39 public static String getS(int action) { 40 String ret = "null"; 41 switch (action) { 42 case MotionEvent.ACTION_CANCEL: 43 ret = "Cancel"; 44 break; 45 case MotionEvent.ACTION_DOWN: 46 ret = "Down"; 47 break; 48 case MotionEvent.ACTION_MOVE: 49 ret = "Move"; 50 break; 51 case MotionEvent.ACTION_UP: 52 ret = "Up"; 53 break; 54 } 55 return ret; 56 } 57 }
继承自LinearLayout,重写了那几个方法。
CustomView.java
1 public class CustomView extends View { 2 private Paint mPaint; 3 4 public CustomView(Context context) { 5 super(context); 6 mPaint = new Paint(); 7 mPaint.setColor(Color.RED); 8 } 9 10 public CustomView(Context context, AttributeSet attrs) { 11 super(context, attrs); 12 mPaint = new Paint(); 13 mPaint.setColor(Color.RED); 14 } 15 16 public CustomView(Context context, AttributeSet attrs, int defStyleAttr) { 17 super(context, attrs, defStyleAttr); 18 mPaint = new Paint(); 19 mPaint.setColor(Color.RED); 20 } 21 22 @Override 23 public void draw(Canvas canvas) { 24 super.draw(canvas); 25 //canvas.drawLine(0, 0, 100, 400, mPaint); 26 canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint); 27 mPaint.setColor(Color.GREEN); 28 canvas.drawText("我是文字", 30, 45, mPaint); 29 canvas.restore(); 30 } 31 32 @Override 33 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 34 //super.onMeasure(widthMeasureSpec, heightMeasureSpec); 35 setMeasuredDimension(getContext().getResources().getDisplayMetrics().widthPixels, 400); 36 } 37 38 @Override 39 public boolean dispatchTouchEvent(MotionEvent event) { 40 Log.e("David--C---------------", "dispatchTouchEvent-" + MyLinear1.getS(event.getAction())); 41 boolean one = super.dispatchTouchEvent(event); 42 Log.e("David--C---------------", "dispatchTouchEvent() super.dispatchTouchEvent(event) = " + one); 43 return one; 44 } 45 46 @Override 47 public boolean onTouchEvent(MotionEvent event) { 48 Log.e("David--C---------------", "onTouchEvent-" + MyLinear1.getS(event.getAction())); 49 return false; 50 } 51 }
这是一个简单地View。
布局文件:当前页面的根View可以认为是MyLinear1,里面只包含了一个子CustomView。至于Activity的根View,我们后续再分析。
1 <?xml version="1.0" encoding="utf-8"?> 2 <com.meituan.david.myapplication.MyLinear1 xmlns:android="http://schemas.android.com/apk/res/android" 3 android:id="@+id/linear" 4 android:layout_width="match_parent" 5 android:layout_height="wrap_content" 6 android:orientation="vertical"> 7 <com.meituan.david.myapplication.CustomView 8 android:layout_width="match_parent" 9 android:layout_height="200dp" /> 10 </com.meituan.david.myapplication.MyLinear1>
上日志:
前提:MyLinear1的onInterceptTouchEvent()方法返回true,意味着Touch事件不会向Children View传递,所以CustomView的两个方法的返回值无所谓了~
1 11-30 18:12:01.014 E/David--MyLinear(20933): dispatchTouchEvent-Down 2 11-30 18:12:02.139 E/David--MyLinear(20933): dispatchTouchEvent-Down 3 11-30 18:12:03.004 E/David--MyLinear(20933): dispatchTouchEvent-Down
触摸(点击、滑动)操作三次打出的log,事件根本没有传递到子View,并且,由于自己MyLinear1不想处理Touch事件,所以只收到了ACTION_DOWN,此后的Touch事件不会再传入了;
2. MyLinear1的dispatchTouchEvent()方法返回false,onTouchEvent返回true,日志如下:
日志和1是一样的,很明显,如果MyLinear1的dispatchTouchEvent()直接返回false,无论其他方法的返回值如何,说明当前ViewGroup不想处理Touch事件,所有后续的Touch事件不会再传入了。
3. MyLinear1的dispatchTouchEvent()方法返回true,onTouchEvent返回false,日志如下:
11-30 18:26:38.451 E/David--MyLinear( 8268): dispatchTouchEvent-Down 11-30 18:26:38.592 E/David--MyLinear( 8268): dispatchTouchEvent-Move 11-30 18:26:38.608 E/David--MyLinear( 8268): dispatchTouchEvent-Move 11-30 18:26:38.625 E/David--MyLinear( 8268): dispatchTouchEvent-Move 11-30 18:26:38.798 E/David--MyLinear( 8268): dispatchTouchEvent-Up
MyLinear1的dispatchTouchEvent()直接返回true,Touch事件源源不断的传入,但是onInterceptTouchEvent()和onTouchEvent()并没有被调用。
根据以上三点,我们可以得出一个结论:
MyLinear1的dispatchTouchEvent()方法,会接受"系统"(暂且认为是系统吧)传入的Touch事件,如果直接返回false,则系统不会再传入Touch事件;返回true,会继续传入。但是,由于没有调用super.dispatchTouchEvent()方法,此Touch事件既不会被拦截/分发,也不会被处理(onInterceptTouchEvent()和onTouchEvent()不会被调用)~
4. MyLinear1的dispatchTouchEvent()方法返回super.dispatchTouchEvent(),onTouchEvent返回false,日志如下:
1 11-30 18:56:04.757 E/David--MyLinear( 8156): dispatchTouchEvent-Down 2 11-30 18:56:04.758 E/David--MyLinear( 8156): onInterceptTouchEvent-Down 3 11-30 18:56:04.758 E/David--MyLinear( 8156): onTouchEvent-Down 4 11-30 18:56:04.758 E/David--MyLinear( 8156): dispatchTouchEvent() super.dispatchTouchEvent(event) = false
另外两个方法得到了调用,但是由于onTouchEvent返回false,说明MyLinear1不想处理后续的Touch事件,所以后续的Touch事件没有传入。仔细看,此时的super.dispatchTouchEvent(event) = false,这也解释了为什么只传入了ACTION_DOWN事件。
5. MyLinear1的dispatchTouchEvent()方法返回super.dispatchTouchEvent(),onTouchEvent返回true,日志如下:
1 11-30 19:02:18.189 E/David--MyLinear(11377): dispatchTouchEvent-Down 2 11-30 19:02:18.189 E/David--MyLinear(11377): onInterceptTouchEvent-Down 3 11-30 19:02:18.189 E/David--MyLinear(11377): onTouchEvent-Down 4 11-30 19:02:18.476 E/David--MyLinear(11377): dispatchTouchEvent() super.dispatchTouchEvent(event)-true 5 6 11-30 19:02:18.505 E/David--MyLinear(11377): dispatchTouchEvent-Move 7 11-30 19:02:18.505 E/David--MyLinear(11377): onTouchEvent-Move 8 11-30 19:02:18.505 E/David--MyLinear(11377): dispatchTouchEvent() super.dispatchTouchEvent(event)-true 9 10 11-30 19:02:18.505 E/David--MyLinear(11377): dispatchTouchEvent-Up 11 11-30 19:02:18.505 E/David--MyLinear(11377): onTouchEvent-Up 12 11-30 19:02:18.505 E/David--MyLinear(11377): dispatchTouchEvent() super.dispatchTouchEvent(event)-true
现在onTouchEvent返回true,说明他愿意处理Touch事件,所以就源源不断的传入了,同时super.dispatchTouchEvent(event)=true,接受系统传入的Touch事件~同时呢,如果当前View决定处理=Touch事件,那么后续传入的Touch事件,就不需要onInterceptTouchEvent了....
根据4、5,我们可以得出一个结论:
dispatchTouchEvent()的返回值和onTouchEvent()的返回值是息息相关的,所以diapatchTouchEvent方法不调用super.dispatchTouchEvent()是没有任何意义的。
以上都是在onInterceptTouchEvent()方法返回true的情况下做的测试,Touch事件根本就没有传递到Children View,那么我们看看onInterceptTouchEvent()方法返回false时,会有什么样的结果。
前提:MyLinear1的dispatchTouchEvent()方法返回super.dispatchTouchEvent(),onInterceptTouchEvent()方法返回false,表示不拦截Touch事件
1. CustomView的dispatchTouchEvent()返回super.dispatchTouchEvent,onTouchEvent返回false,MyLinear1的onTouchEvent返回true,日志如下:
1 11-30 19:19:54.430 E/David--MyLinear( 1860): dispatchTouchEvent-Down 2 11-30 19:19:54.430 E/David--MyLinear( 1860): onInterceptTouchEvent-Down 3 11-30 19:19:54.430 E/David--C---------------( 1860): dispatchTouchEvent-Down 4 11-30 19:19:54.430 E/David--C---------------( 1860): onTouchEvent-Down 5 11-30 19:19:54.430 E/David--C---------------( 1860): dispatchTouchEvent() super.dispatchTouchEvent(event) = false 6 11-30 19:19:54.430 E/David--MyLinear( 1860): onTouchEvent-Down 7 8 11-30 19:19:54.659 E/David--MyLinear( 1860): dispatchTouchEvent() super.dispatchTouchEvent(event) = true 9 11-30 19:19:54.680 E/David--MyLinear( 1860): dispatchTouchEvent-Move 10 11-30 19:19:54.680 E/David--MyLinear( 1860): onTouchEvent-Move 11 11-30 19:19:54.680 E/David--MyLinear( 1860): dispatchTouchEvent() super.dispatchTouchEvent(event) = true 12 11-30 19:19:54.794 E/David--MyLinear( 1860): dispatchTouchEvent-Move 13 11-30 19:19:54.794 E/David--MyLinear( 1860): onTouchEvent-Move 14 15 11-30 19:19:54.794 E/David--MyLinear( 1860): dispatchTouchEvent() super.dispatchTouchEvent(event) = true 16 11-30 19:19:54.825 E/David--MyLinear( 1860): dispatchTouchEvent-Up 17 11-30 19:19:54.825 E/David--MyLinear( 1860): onTouchEvent-Up 18 11-30 19:19:54.825 E/David--MyLinear( 1860): dispatchTouchEvent() super.dispatchTouchEvent(event) = true
事件顺利的传到Custom View,但是由于CustomView的onTouchEvent返回false,意味着他不想处理后续Touch事件,所以,CustomView的dispatchTouchEvent()返回false,Touch事件不再传入到CustomView。那么传入的ACTION_DOWN和后续的Touch事件怎么办呢,总不能没人管吧?其实,当Child View不想处理ACTION_DOWN事件时,ACTION_DOWN就会被回传至Father View,很显然,CustomView的父View就是MyLinear1了,所以MyLinear1的onTouchEvent收到了该事件。如果MyLinear的onTouchEvent决定处理Touch事件,那么就会消化ACTION_DOWN事件,同时后续的Touch事件会源源不断的传给MyLienar1,与CustomView就没有半毛钱关系了~日志也是这么显示的。
2. 和1一样的条件,如果MyLinear1不愿意处理Touch事件呢?onTouchEvent()返回false,我们看日志:
1 11-30 19:28:42.199 E/David--MyLinear(11273): dispatchTouchEvent-Down 2 11-30 19:28:42.199 E/David--MyLinear(11273): onInterceptTouchEvent-Down 3 11-30 19:28:42.199 E/David--C---------------(11273): dispatchTouchEvent-Down 4 11-30 19:28:42.199 E/David--C---------------(11273): onTouchEvent-Down 5 11-30 19:28:42.199 E/David--C---------------(11273): dispatchTouchEvent() super.dispatchTouchEvent(event) = false 6 11-30 19:28:42.199 E/David--MyLinear(11273): onTouchEvent-Down 7 11-30 19:28:42.199 E/David--MyLinear(11273): dispatchTouchEvent() super.dispatchTouchEvent(event) = false
CustomView不愿处理的Touch事件被回传至MyLinear1,这没问题,但是MyLinear1也不愿意处理Touch事件,所以onTouchEvent返回false,同时super.dispatchTouchEvent(event)返回false,后续的Touch事件就不会再传入了~
3. CustomView的dispatchTouchEvent()返回super.dispatchTouchEvent,onTouchEvent返回true,MyLinear1的onTouchEvent返回false,日志如下:
1 12-01 12:00:30.735 E/David--MyLinear( 363): dispatchTouchEvent-Down 2 12-01 12:00:30.735 E/David--MyLinear( 363): onInterceptTouchEvent-Down 3 12-01 12:00:30.735 E/David--C---------------( 363): dispatchTouchEvent-Down 4 12-01 12:00:30.735 E/David--C---------------( 363): onTouchEvent-Down 5 12-01 12:00:30.735 E/David--C---------------( 363): dispatchTouchEvent() super.dispatchTouchEvent(event) = true 6 12-01 12:00:30.735 E/David--MyLinear( 363): dispatchTouchEvent() super.dispatchTouchEvent(event) = true 7 8 12-01 12:00:30.958 E/David--MyLinear( 363): dispatchTouchEvent-Move 9 12-01 12:00:30.958 E/David--MyLinear( 363): onInterceptTouchEvent-Move 10 12-01 12:00:30.958 E/David--C---------------( 363): dispatchTouchEvent-Move 11 12-01 12:00:30.958 E/David--C---------------( 363): onTouchEvent-Move 12 12-01 12:00:30.958 E/David--C---------------( 363): dispatchTouchEvent() super.dispatchTouchEvent(event) = true 13 12-01 12:00:30.958 E/David--MyLinear( 363): dispatchTouchEvent() super.dispatchTouchEvent(event) = true 14 15 12-01 12:00:30.974 E/David--MyLinear( 363): dispatchTouchEvent-Move 16 12-01 12:00:30.974 E/David--MyLinear( 363): onInterceptTouchEvent-Move 17 12-01 12:00:30.974 E/David--C---------------( 363): dispatchTouchEvent-Move 18 12-01 12:00:30.974 E/David--C---------------( 363): onTouchEvent-Move 19 12-01 12:00:30.974 E/David--C---------------( 363): dispatchTouchEvent() super.dispatchTouchEvent(event) = true 20 12-01 12:00:30.974 E/David--MyLinear( 363): dispatchTouchEvent() super.dispatchTouchEvent(event) = true 21 22 12-01 12:00:30.992 E/David--MyLinear( 363): dispatchTouchEvent-Move 23 12-01 12:00:30.992 E/David--MyLinear( 363): onInterceptTouchEvent-Move 24 12-01 12:00:30.992 E/David--C---------------( 363): dispatchTouchEvent-Move 25 12-01 12:00:30.992 E/David--C---------------( 363): onTouchEvent-Move 26 12-01 12:00:30.992 E/David--C---------------( 363): dispatchTouchEvent() super.dispatchTouchEvent(event) = true 27 12-01 12:00:30.992 E/David--MyLinear( 363): dispatchTouchEvent() super.dispatchTouchEvent(event) = true 28 29 12-01 12:00:31.026 E/David--MyLinear( 363): dispatchTouchEvent-Up 30 12-01 12:00:31.026 E/David--MyLinear( 363): onInterceptTouchEvent-Up 31 12-01 12:00:31.026 E/David--C---------------( 363): dispatchTouchEvent-Up 32 12-01 12:00:31.026 E/David--C---------------( 363): onTouchEvent-Up 33 12-01 12:00:31.026 E/David--C---------------( 363): dispatchTouchEvent() super.dispatchTouchEvent(event) = true 34 12-01 12:00:31.026 E/David--MyLinear( 363): dispatchTouchEvent() super.dispatchTouchEvent(event) = true
CustomView收到Touch事件,而且想处理它,onTouchEvent返回true,此时Touch事件会源源不断地传至CustomView,CustomView和MyLinear1的dispatchTouchEvent都返回true~有两个新特点:
1、MyLinear1的onInterceptTouchEvent每次都会被调用,这说明,如果ViewGroup决定自己处理Touch事件,那么ACTION_DOWN之后的事件都不会经过onInterceptTouchEvent。但是Children View就不一样了,每次都得被拦截一下,谁让你是Children呢~
2、一旦Children View开始处理Touch事件,就没有MyLinear1的onTouchEvent什么事了。
本文总结:
经过上面的分析,应该是说清楚了dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()方法的使用情况了,记住,这三个方法的调用是有顺序的。对于简单的自定义View或者ViewGroup的需求,应该已经能满足需求了。毕竟,最好是不要直接完全重写dispatchTouchEvent或者onTouchEvent,可以适当的加一些判断,但是最终还是要调用View的方法的,这已经能满足绝大多数的需求了。下一篇,咱们仔细研究一下dispatchTouchEvent()和onTouchEvent()方法的代码