欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ViewPager嵌套HorizontalScrollView滑动冲突以及点击抖动问题解决

程序员文章站 2024-01-28 18:49:28
...

ViewPager嵌套HorizontalScrollView滑动冲突以及点击抖动问题解决

ViewPager嵌套HorizontalScrollView滑动冲突以及点击抖动问题解决

项目中有这样一个礼物弹窗,可选择角色的数量不固定,需要左右滑动,加上弹窗两个TAB可以左右滑动,所以存在滑动冲突。

弹窗主体使用viewpager,角色选择栏使用HorizontalScrollView,嵌套关系如下图所示。

礼物部分(忽略空态):
- ViewPager          //弹窗主体
    - RelativeLayout //礼物TAB
        - Gridview   //礼物列表
        - LinearLayout  //角色选择栏
            -TextView   //"送给"
            - HorizontalScrollView //水平滑动view
                -LinearLayout      //角色列表
        - BottomView  //底部复杂按钮

问题一:滑动冲突

如果不做任何处理,写完布局以后,HorizontalScrollView的左右滑动事件会被ViewPager吃掉,角色列表并不能滑动,就是滑动冲突了。

解决方案很简单,把ViewPager吃掉的触摸事件还给HorizontalScrollView。做几件事情:
- 找到触摸事件被吃掉之前的时机(方法)
- 判断触摸事件是否应该被HorizontalScrollVIew处理
- 如果是HorizontalScrollView的事件,就给它处理,否则按原有逻辑处理

1、吃掉触摸事件之前的时机就是 RelativeLayout的onInterceptTouchEvent方法。
2、判断是否交给HorizontalScrollView,只需要计算触摸位置是否为HorizontalScrollVIew

  //RelativeLayout
  @Override
  public boolean onInterceptTouchEvent(MotionEvent ev) {
    if (isTouchRole(ev)) { //判断点击了ScrollView
      //交给ScrollView处理
      mRoleListScrollView.onTouchEvent(ev);
      return false;
    }

    return super.onInterceptTouchEvent(ev);
  }

  //判断点击区域是否在HorizontalScrollView
  public boolean isTouchRole(MotionEvent ev) {
    RectF rect = calcViewScreenLocation(mRoleContainer);
    boolean isInViewRect = rect.contains(ev.getRawX(), ev.getRawY());

    return isInViewRect;
  }

  public static RectF calcViewScreenLocation(View view) {
    int[] location = new int[2];
    // 获取控件在屏幕中的位置,返回的数组分别为控件左顶点的 x、y 的值
    view.getLocationOnScreen(location);
    return new RectF(location[0], location[1], location[0] + view.getWidth(),
        location[1] + view.getHeight());
  }

问题二:部分机型点击HorizonScrollView时会抖动,或者滑动,如小米,三星等

经过调试打点发现,出问题的手机在onInterceptTouchEvent方法时,MotionEvent的Action均为ACTION_MOVE,而正常手机为ACTION_DOWN,这也很好的说明了ScrollView为什么会滑动。

所以再对onInterceptTouchEvent进行一些的处理,防止这种情况出现:

  @Override
  public boolean onInterceptTouchEvent(MotionEvent ev) {
    if (isTouchRole(ev)) {
      //适配
      switch (ev.getAction()){
        case ACTION_DOWN:
          break;
        case ACTION_UP:
          mRoleListScrollView.onTouchEvent(ev);
          break;
        case ACTION_MOVE:
          break;
      }
      return false;
    }

    return super.onInterceptTouchEvent(ev);
  }