Android滑动冲突解决

本文介绍了Android应用中常见的滑动冲突场景及其处理规则,并详细探讨了外部拦截法与内部拦截法两种解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、滑动冲突的场景

(1) 外部滑动方向和内部滑动方向不一致;

(2) 外不滑动方向和内部滑动方向一致;

(3) 上边两种情况的集合

图解如下:



场景1: 主要是将viewpage和fragment配合使用所组成的滑动效果,主流应用几乎都会使用这个效果,在这个效果中可以通过左右滑动来切换页面,而每个页面内部都有listview,但是因为这种情况viewpage已经做了滑动冲突的处理,所以我们不用解决,如果我们采用的是scrollerview,那么我们就要解决滑动冲突。否则就会造成内外两层只有一层能狗滑动。场景三是slidermenu和viewpage,listview三种情况,看起来很复杂,但是可以分开来看。

2、滑动冲突的处理规则

对于场景一来说,我们可以根据水平滑动或者竖直滑动来拦截触发事件,根据滑动两个点之间的坐标就可以知道是水平滑动还是竖直滑动,我们可以根据华东路径和水平方向的夹角,也可以根据水平方向和竖直方向滑动的距离来判断,特殊情况下还可以根据水平或者竖直的速度差来判断。

对于场景二来说,比较摊位数,不弄用以上的方法来判断,他需要在业务上找到突破点,当处于某种状态时,需要响应用户的外部滑动,再摸种情况下需要响应用户的内部滑动,


3、滑动冲突的解决方法

(1)外部拦截法

就是所有的点击事件都要经过父控件的处理,如果父容器需要此事件就拦截,不需要此事件就不拦截,这样就可以解决滑动冲突的问题,这种方法比较适合于事件的分发机制,外部拦截法需要重写父容器的onintercepttouchevent方法,在内部做相应的拦截;伪代码如下:

	// 父容器是否需要此事件
	boolean state = false;
	int mLastxintercept = 0;
	int mLastintercept = 0;

	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		boolean intercepted = false;
		int x = (int) ev.getX();
		int y = (int) ev.getY();
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			intercepted = false;
			break;
		case MotionEvent.ACTION_MOVE:
			if (state) {
				intercepted = true;
			} else {
				intercepted = false;
			}
			break;
		case MotionEvent.ACTION_UP:
			intercepted = false;
			break;

		default:
			break;
		}
		mLastX = x;
		mLastY = y;
		return intercepted;
	}

这里需要考虑一种情况,就是当事件交由子元素进行处理,如果父容器在actionup 时返回了true,那么就会导致子元素无法收到actionup事件,这个时候子元素中的onclick事件将不会响应,但父容器比较特殊,当有一个事件被拦截,那么其他的事件都会交给他来处理,尽管onintercepttouchevent返回false;

(2)内部拦截法

这种方法就是父容器不拦截任何事件,事件全部交给子元素来处理,如果子元素需要就直接消耗掉,如果子元素不处理就交给父容器,这种方法和Android的事件分发不一致,需要配合requestdisallowintercepttouchevent方法才能正常工作,使用起来稍微复杂,伪代码如下所示:

@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		boolean consume = false;
		int x = (int) event.getX();
		int y = (int) event.getY();
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			super.requestDisallowInterceptTouchEvent(true);
			break;
		case MotionEvent.ACTION_MOVE:

			int deltax = x - mlastx;
			int deltay = mLastY;
			// 是否需要此事件
			if (state) {
				super.requestDisallowInterceptTouchEvent(false);
			}
			break;
		case MotionEvent.ACTION_UP:

			break;
		default:
			break;
		}
		mlastx = x;
		mLastY = y;
		return super.onInterceptTouchEvent(event);
	}

上面是典型的代码内部拦截方法,当面对不同的策略时只需要修改里边的条件就行,其他的不需要改动也不能挨冻,除了子元素要处理外,父元素也要默认拦截了actiondown以外的其他事件,这样当子元素super.requestDisallowInterceptTouchEvent(false);时,父元素才能继续拦截所需要的事件。父元素不能拦截actiondown事件,是因为actiondown事件并不受flagdisallowintercept的影响,当父元素一旦拦截了actiondown事件,那么所有的事件都不能传到子元素中去。这样内部拦截就不能起作用了。父元素作如下修改:

	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		
		int action = ev.getAction();
		if (action == MotionEvent.ACTION_DOWN) {
			return false;

		} else {
			return true;
		}
	}

下一节我们将会用实列来演示和讲解view的滑动。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值