为什么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是在一个事件系列中间使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在addOnLayoutChangeListener方法中调用removeView方法失效的原因是,addOnLayoutChangeListener监听的是布局的改变,而removeView方法是用于从父容器中移除视图的。当您在addOnLayoutChangeListener回调方法中调用removeView时,可能导致布局发生改变,从而触发addOnLayoutChangeListener的再次回调,形成一个循环,导致移除视图的操作失效。 要解决这个问题,您可以在addOnLayoutChangeListener回调方法中使用一个标志位来控制移除视图的操作。例如,您可以添加一个boolean类型的变量来判断是否需要执行移除视图的操作。以下是一个示例代码: ```java FlexboxLayout flexboxLayout = findViewById(R.id.flexboxLayout); boolean isRemovingView = false; // 标志位 flexboxLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { @Override public void onLayoutChange(View view, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { if (isRemovingView) { return; } // 根据条件判断是否需要移除视图 if (/* 需要移除视图的条件 */) { isRemovingView = true; flexboxLayout.removeView(childView); isRemovingView = false; } } }); ``` 在上述代码中,我们添加了一个名为isRemovingView的标志位,并在执行移除视图操作时进行判断。如果标志位为true,则直接返回,避免再次触发addOnLayoutChangeListener回调。这样可以确保移除视图的操作只执行一次,避免了循环调用的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值