关于手势冲突问题

  • TextView的滑动和RecyclerView冲突
  1. 问题描述:RecycleView中使用了TextView,而TextView大小有限,要求文本支持滚动,此时会与Recycler的滑动冲突;
  2. 问题解决:监听TextView文本的滚动事件,如果是TextView需要滚动时,禁止父控件(RecyclerView)的滑动,否则允许父控件滑动;
tvContent.setMovementMethod(ScrollingMovementMethod.getInstance());
tvContent.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                v.getParent().requestDisallowInterceptTouchEvent(true);
                switch (event.getAction()) {
                    case MotionEvent.ACTION_UP:
                        v.getParent().requestDisallowInterceptTouchEvent(false);
                        break;
                }
                return false;
            }
        });
  • Scrollview的滑动和RecyclerView冲突
  1. 问题描述:一个比较长的界面一般都是Scrollview嵌套RecyclerView来解决.不过这样的UI并不是我们开发人员想看到的,实际上嵌套之后.因为Scrollview和RecyclerView都是滑动控件.会有一点滑动上的冲突.导致滑动起来有些卡顿.
  2. 问题解决:禁止RecycleView的滑动,我们重写一下LayoutManager就行了;
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false) {
            @Override
            public boolean canScrollVertically() {
                return false;
            }
        };
recyclerview.setLayoutManager(linearLayoutManager);
recyclerview.setAdapter(tempCommonAdapter);
  •  ViewPager和 SwipeRefreshLayout冲突
  1. 问题描述: 当 SwipeRefreshLayout 中有 ViewPager 控件, 两者的滑动会相互冲突. 具体表现为 ViewPager 的左右滑动不顺畅, 容易被 SwipeRefreshLayout 拦截(即出现刷新的 View ).
  2. 问题解决: ViewPager 本身是处理了滚动事件的冲突, 它在横向滑动时会调用 requestDisallowInterceptTouchEvent() 方法使父控件不拦截当前的 Touch 事件序列. 但是 SwipeRefreshLayout 的 requestDisallowInterceptTouchEvent() 方法置空了, 所以仍然会拦截当前的 Touch 事件序列.
1. //非法按键
2. private static final int INVALID_POINTER = -1;
3.
4. //dispatch方法记录第一次按下的x
5. private float mInitialDisPatchDownX;
6.
7. //dispatch方法记录第一次按下的y
8. private float mInitialDisPatchDownY;
9.
10. //dispatch方法记录的手指
11. private int mActiveDispatchPointerId = INVALID_POINTER;
12.
13. //是否请求拦截
14. private boolean hasRequestDisallowIntercept = false;
15.
16. @Override
17. public void requestDisallowInterceptTouchEvent(boolean b) {
18.     hasRequestDisallowIntercept = b;
19.     // Nope.
20. }
21.
22. @Override
23. public boolean dispatchTouchEvent(MotionEvent ev) {
24.     switch (ev.getAction()) {
25.         case MotionEvent.ACTION_DOWN:
26.             mActiveDispatchPointerId = MotionEventCompat.getPointerId(ev, 0);
27.             final float initialDownX = getMotionEventX(ev, mActiveDispatchPointerId);
28.             if (initialDownX != INVALID_POINTER) {
29.                 mInitialDisPatchDownX = initialDownX;
30.             }
31.             final float initialDownY = getMotionEventY(ev, mActiveDispatchPointerId);
32.             if (mInitialDisPatchDownY != INVALID_POINTER) {
33.                 mInitialDisPatchDownY = initialDownY;
34.             }
35.             break;
36.         case MotionEvent.ACTION_MOVE:
37.             if (hasRequestDisallowIntercept) {
38.                 //解决viewPager滑动冲突问题
39.                 final float x = getMotionEventX(ev, mActiveDispatchPointerId);
40.                 final float y = getMotionEventY(ev, mActiveDispatchPointerId);
41.                 if (mInitialDisPatchDownX != INVALID_POINTER && x != INVALID_POINTER &&
42.                         mInitialDisPatchDownY != INVALID_POINTER && y != INVALID_POINTER) {
43.                     final float xDiff = Math.abs(x – mInitialDisPatchDownX);
44.                     final float yDiff = Math.abs(y – mInitialDisPatchDownY);
45.                     if (xDiff > mTouchSlop && xDiff * 0.7f > yDiff) {
46.                         //横向滚动不需要拦截
47.                         super.requestDisallowInterceptTouchEvent(true);
48.                     } else {
49.                         super.requestDisallowInterceptTouchEvent(false);
50.                     }
51.                 } else {
52.                     super.requestDisallowInterceptTouchEvent(false);
53.                 }
54.             }
55.             break;
56.         case MotionEvent.ACTION_UP:
57.         case MotionEvent.ACTION_CANCEL:
58.             if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) {
59.                 hasRequestDisallowIntercept = false;
60.             }
61.             break;
62.     }
63.
64.     return super.dispatchTouchEvent(ev);
65. }
66.
67. private float getMotionEventY(MotionEvent ev, int activePointerId) {
68.     final int index = MotionEventCompat.findPointerIndex(ev, activePointerId);
69.     if (index < 0) {
70.         return -1;
71.     }
72.     return MotionEventCompat.getY(ev, index);
73. }
74.
75. private float getMotionEventX(MotionEvent ev, int activePointerId) {
76.     final int index = MotionEventCompat.findPointerIndex(ev, activePointerId);
77.     if (index < 0) {
78.         return -1;
79.     }
80.     return MotionEventCompat.getX(ev, index);
81. }
  • RecyclerView嵌套ViewPager的冲突
  1. 问题描述: 当用户滑动 RecyclerView 后放开手指, RecyclerView 会继续滑动并处于 Fling 状态. 此时用户重新触摸屏幕, RecyclerView 滑动停止, 但是无法左右滑动 ViewPager , 只能上下滑动 RecyclerView .  当用户重新触摸屏幕, 此时 RecyclerView 的 onInterceptTouchEvent() 方法还是返回了 true , 所以 ViewGroup 还是继续拦截了事件, 导致 ViewPager 无法处理.
  2. 问题解决: 如果是 Fling 状态的 RecyclerView , 在处理 ACTION_DOWN 事件时, 应该与 IDLE 状态下保持一致. Fling 状态下处理 ACTION_DOWN , onInterceptTouchEvent() 方法应该返回 false.
1. @Override
2. public boolean onInterceptTouchEvent(MotionEvent e) {
3.     //isScrolling 为 true 表示是 Fling 状态
4.     boolean isScrolling = getScrollState() == SCROLL_STATE_SETTLING;
5.     boolean ans = super.onInterceptTouchEvent(e);
6.     if (ans && isScrolling && e.getAction() == MotionEvent.ACTION_DOWN) {
7.         //先调用 onTouchEvent() 使 RecyclerView 停下来
8.         onTouchEvent(e);
9.         //反射恢复 ScrollState
10.         try {
11.             Field field = RecyclerView.class.getDeclaredField(“mScrollState”);
12.             field.setAccessible(true);
13.             field.setInt(this, SCROLL_STATE_IDLE);
14.         } catch (NoSuchFieldException e1) {
15.             e1.printStackTrace();
16.         } catch (IllegalAccessException e1) {
17.             e1.printStackTrace();
18.         }
19.         return false;
20.     }
21.     return ans;
22. }

留下评论

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理