onTouch和onTouchEvent的关系

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/nongminkouhao/article/details/85015936

处理触摸时间通常有两个做法,一是给控件设置触摸事件的监听器,二是覆写onTouchEvent方法,那么监听器中的onTouch方法和View本身的onTouchEvent方法都是处理事件,它们之间有什么区别和联系呢?我们自定义一个MyView,既设置触摸事件的监听,也实现其onTouchEvent方法,通过log检验它们的调用顺序。

MyView.java

public class MyView extends View {
    private static final String TAG = "MyView";
    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.d(TAG,"onTouchEvent");
        return super.onTouchEvent(event);
    }
}

MainActivity.java

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //设置触摸事件的监听
        findViewById(R.id.myView).setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.d(TAG,"onTouch:");
                return true;
            }
        });

    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:tools="http://schemas.android.com/tools"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical"
              tools:context="com.hj.test.test.MainActivity2">

    <com.hj.test.test.MyView
        android:id="@+id/myView"
        android:layout_width="match_parent"
        android:layout_height="120dp"
        android:background="@android:color/holo_red_light"
        />

</LinearLayout>

当onTouch方法返回false时,会打印onTouch方法的log,再打印onTouchEvent方法的log。当onTouch方法返回true时,只会打印onTouch方法的log。

为什么是这样的逻辑呢?我们从View类中的dispatchTouchEvent的方法中找到答案,代码如下:
//View.java

public boolean dispatchTouchEvent(MotionEvent event) {
        // If the event should be handled by accessibility focus first.
        if (event.isTargetAccessibilityFocus()) {
            // We don't have focus or no virtual descendant has it, do not handle the event.
            if (!isAccessibilityFocusedViewOrHost()) {
                return false;
            }
            // We have focus and got the event, then use normal event dispatch.
            event.setTargetAccessibilityFocus(false);
        }

        boolean result = false;

        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onTouchEvent(event, 0);
        }

        final int actionMasked = event.getActionMasked();
        if (actionMasked == MotionEvent.ACTION_DOWN) {
            // Defensive cleanup for new gesture
            stopNestedScroll();
        }

        if (onFilterTouchEventForSecurity(event)) {
            //noinspection SimplifiableIfStatement
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {//先回调onTouch方法
                result = true;
            }
	    //如果View时enable状态并且onTouch返回的时true,那么就不会调用onTouchEvent的方法
            if (!result && onTouchEvent(event)) {
                result = true;
            }
        }

        if (!result && mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
        }

        // Clean up after nested scrolls if this is the end of a gesture;
        // also cancel it if we tried an ACTION_DOWN but we didn't want the rest
        // of the gesture.
        if (actionMasked == MotionEvent.ACTION_UP ||
                actionMasked == MotionEvent.ACTION_CANCEL ||
                (actionMasked == MotionEvent.ACTION_DOWN && !result)) {
            stopNestedScroll();
        }

        return result;
    }

View在分发事件时,在监听器不为空的情况下,会先调用触摸事件监听器的onTouch方法,如果onTouch返回true,则表示事件在监听器中消费了,result会被标记会true,那么后面就不会调用onTouchEvent方法,反之则会调用。

看到了记录了,希望对你与帮助
参考《Android应用开发进阶》

猜你喜欢

转载自blog.csdn.net/nongminkouhao/article/details/85015936