Android中view的Touch事件傳遞順序

先看一下ViewGroup的dispatchTouchEvent的關鍵源碼: html

public boolean dispatchTouchEvent(MotionEvent ev) {
	...
        if (action == MotionEvent.ACTION_DOWN) {
	...
       	    if (disallowIntercept || !onInterceptTouchEvent(ev)) {
                final View[] children = mChildren;
                final int count = mChildrenCount;
                for (int i = count - 1; i >= 0; i--) {
                    final View child = children[i];
                    if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
                            || child.getAnimation() != null) {
                       ...
                            if (child.dispatchTouchEvent(ev))  {
                                // Event handled, we have a target now.
                                mMotionTarget = child;
                                return true;
                            }
                    }
                }
            }
        }
	...
        final View target = mMotionTarget;
        if (target == null) {
		...
            return super.dispatchTouchEvent(ev);
        }
        if (!disallowIntercept && onInterceptTouchEvent(ev)) {
            ...
            if (!target.dispatchTouchEvent(ev)) {
                // target didn't handle ACTION_CANCEL. not much we can do
                // but they should have.
            }
            // clear the target
            mMotionTarget = null;
            // Don't dispatch this event to our own view, because we already
            // saw it when intercepting; we just want to give the following
            // event to the normal onTouchEvent().
            return true;
        }
	...
        return target.dispatchTouchEvent(ev);
    }
根據以上代碼可知,若是onInterceptTouchEvent方法返回true,會直接調用當前ViewGroup的onTouch方法,不然則會依次調用其內包含的子控件的dispatchTouchEvent方法。我寫了一個測試用例,ViewGroup的onInterceptTouchEvent方法與全部View的onTouch方法都打了Log:
<?xml version="1.0" encoding="utf-8"?>
<org.gavin.test.view.MyScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

	<org.gavin.test.view.MyLinearLayout
	    android:layout_width="fill_parent"
	    android:layout_height="fill_parent"
	    android:orientation="vertical">
	    <org.gavin.test.view.MyImageView
	        android:layout_width="wrap_content"
	        android:layout_height="wrap_content"
	        android:src="@drawable/ic_launcher"></org.gavin.test.view.MyImageView>
	</org.gavin.test.view.MyLinearLayout>

</org.gavin.test.view.MyScrollView>
Log信息:

I/MyScrollView(26001): onInterceptTouchEvent:MotionEvent{404ea7c8 action=0 x=34.215885 y=51.963867 pressure=0.14117648 size=0.1}
I/MyLinearLayout(26001): onInterceptTouchEvent:MotionEvent{404ea7c8 action=0 x=34.215885 y=51.963867 pressure=0.14117648 size=0.1}
I/MyImageView(26001): onTouchEvent:MotionEvent{404ea7c8 action=0 x=34.215885 y=51.963867 pressure=0.14117648 size=0.1}
I/MyLinearLayout(26001): onTouchEvent:MotionEvent{404ea7c8 action=0 x=34.215885 y=51.963867 pressure=0.14117648 size=0.1}
I/MyScrollView(26001): onTouchEvent:MotionEvent{404ea7c8 action=0 x=34.215885 y=51.963867 pressure=0.14117648 size=0.1} java

若是MyLinearLayout的onInterceptTouchEvent方法返回true: android

11-04 14:05:08.389: I/MyScrollView(26297): onInterceptTouchEvent:MotionEvent{404e9ed0 action=0 x=24.439919 y=41.980873 pressure=0.13333334 size=0.15}
11-04 14:05:08.389: I/MyLinearLayout(26297): onInterceptTouchEvent:MotionEvent{404e9ed0 action=0 x=24.439919 y=41.980873 pressure=0.13333334 size=0.15}
11-04 14:05:08.397: I/MyLinearLayout(26297): onTouchEvent:MotionEvent{404e9ed0 action=0 x=24.439919 y=41.980873 pressure=0.13333334 size=0.15}
11-04 14:05:08.397: I/MyScrollView(26297): onTouchEvent:MotionEvent{404e9ed0 action=0 x=24.439919 y=41.980873 pressure=0.13333334 size=0.15} 測試

OK,再看這段代碼: this

if (child.dispatchTouchEvent(ev))  {
                                // Event handled, we have a target now.
                                mMotionTarget = child;
                                return true;
                            }
從這段代碼能夠看出,若是某個子控件的dispatchTouchEvent方法返回true,則中斷之後的消息傳遞。並在下一個非ACTION_DOWN事件直接調用此子控件的dispatchTouchEvent方法。一個View的dispatchTouchEvent返回true,主要多是onTouch方法返回true。若是咱們把MyImageView的onTouchEvent返回值改成true:

I/MyScrollView(26393): onInterceptTouchEvent:MotionEvent{404eb2b0 action=0 x=32.749493 y=51.05632 pressure=0.11764707 size=0.1}
/MyLinearLayout(26393): onInterceptTouchEvent:MotionEvent{404eb2b0 action=0 x=32.749493 y=51.05632 pressure=0.11764707 size=0.1}
I/MyImageView(26393): onTouchEvent:MotionEvent{404eb2b0 action=0 x=32.749493 y=51.05632 pressure=0.11764707 size=0.1} spa

相關文章
相關標籤/搜索