@TryLoveCatch
2022-05-17T02:28:50.000000Z
字数 2467
阅读 819
Android知识体系
滑动冲突有两种场景:
有小伙伴肯定有疑问,ViewPager带ListView并没有出现滑动冲突啊。
那是因为ViewPager已经为我们处理了滑动冲突!如果我们自己定义一个水平滑动的ViewGroup内部再使用ListView,那么是一定需要处理滑动冲突的。
由于外部与内部的滑动方向不一致,那么我们可以根据当前滑动方向,水平还是垂直来判断这个事件到底该交给谁来处理。
如何判断滑动的方向是水平还是垂直?
由于外部与内部的滑动方向一致,那么不能根据滑动角度、距离差或者速度差来判断。这种情况下必需通过业务逻辑来进行判断。比较常见ScrollView嵌套了ListView。
父View根据需要对事件进行拦截。逻辑处理放在父View的onInterceptTouchEvent方法中。我们只需要重写父View的onInterceptTouchEvent方法,并根据逻辑需要做相应的拦截即可。
public boolean onInterceptTouchEvent(MotionEvent event) {boolean intercepted = false;int x = (int) event.getX();int y = (int) event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN: {intercepted = false;break;}case MotionEvent.ACTION_MOVE: {if (满足父容器的拦截要求) {intercepted = true;} else {intercepted = false;}break;}case MotionEvent.ACTION_UP: {intercepted = false;break;}default:break;}mLastXIntercept = x;mLastYIntercept = y;return intercepted;}
- ACTION_DOWN 一定返回false,不要拦截它,否则根据View事件分发机制,后续ACTION_MOVE 与 ACTION_UP事件都将默认交给父View去处理!
- 原则上ACTION_UP也需要返回false,如果返回true,并且ACTION_MOVE交给子View处理,那么子View将接收不到ACTION_UP事件,子View的onClick事件也无法触发。而父View不一样,如果父View在ACTION_MOVE中开始拦截事件,那么后续ACTION_UP也将默认交给父View处理!
父View不拦截任何事件,所有事件都传递给子View,子View根据需要决定是自己消费事件还是给父View处理。
这需要子View使用requestDisallowInterceptTouchEvent方法才能正常工作。
子View的dispatchTouchEvent方法的伪代码:
public boolean dispatchTouchEvent(MotionEvent event) {int x = (int) event.getX();int y = (int) event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN: {parent.requestDisallowInterceptTouchEvent(true);break;}case MotionEvent.ACTION_MOVE: {int deltaX = x - mLastX;int deltaY = y - mLastY;if (父容器需要此类点击事件) {parent.requestDisallowInterceptTouchEvent(false);}break;}case MotionEvent.ACTION_UP: {break;}default:break;}mLastX = x;mLastY = y;return super.dispatchTouchEvent(event);}
父View需要重写onInterceptTouchEvent方法:
public boolean onInterceptTouchEvent(MotionEvent event) {int action = event.getAction();if (action == MotionEvent.ACTION_DOWN) {return false;} else {return true;}}
