为什么requestDisallowInterceptTouchEvent方法会失效

requestDisallowInterceptTouchEvent方法是用来禁止或允许ViewGroup是否能拦截事件,通常用来处理滑动冲突.但如果在ViewGroup初始化之后立即就调用这个方法会发现这个方法并没有起到作用.

示例

class MyLayout extends LinearLayout {

	public MyLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		return true;
	}

}
	//主程序:
		LinearLayout li = (LinearLayout) findViewById(R.id.li);
		li.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				Log.e(TAG, "click layout");
			}
		});
		//不允许li拦截事件
		li.requestDisallowInterceptTouchEvent(true);
		
		btn.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				Log.e(TAG, "click");
			}
		});
		

LinearLayout 的onInterceptTouchEvent已重写成返回true的形式
上面这段程序运行的结果是打印click layout,明明不允许拦截事件,为什么点击事件还是不能传递给button呢?翻看ViewGroup的dispatchTouchEvent方法源码发现了答案,源码中有这么一段:

		boolean handled = false;
        if (onFilterTouchEventForSecurity(ev)) {
            final int action = ev.getAction();
            final int actionMasked = action & MotionEvent.ACTION_MASK;

            // Handle an initial down.
            if (actionMasked == MotionEvent.ACTION_DOWN) {
                // Throw away all previous state when starting a new touch gesture.
                // The framework may have dropped the up or cancel event for the previous gesture
                // due to an app switch, ANR, or some other state change.
                cancelAndClearTouchTargets(ev);
                resetTouchState();
            }

            // Check for interception.
            final boolean intercepted;
            if (actionMasked == MotionEvent.ACTION_DOWN
                    || mFirstTouchTarget != null) {
                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                if (!disallowIntercept) {
                    intercepted = onInterceptTouchEvent(ev);
                    ev.setAction(action); // restore action in case it was changed
                } else {
                    intercepted = false;
                }
            } else {
                // There are no touch targets and this action is not an initial down
                // so this view group continues to intercept touches.
                intercepted = true;
            }

在进行是否拦截之前,有一个判断,判断当前事件是否是 MotionEvent.ACTION_DOWN,如果是则调用resetTouchState方法,查看resetTouchState方法源码:

private void resetTouchState() {
        clearTouchTargets();
        resetCancelNextUpFlag(this);
        mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
    }

原来在这个方法里面又重新允许拦截事件了,所以说我们自己代码里的请求根本就没用,默认情况下就是允许拦截的,正确使用requestDisallowInterceptTouchEvent是在一个事件系列中间使用。

你可能感兴趣的:(Android)