当前位置: 移动技术网 > IT编程>移动开发>Android > Android中ViewPager带来的滑动卡顿问题解决要点解析

Android中ViewPager带来的滑动卡顿问题解决要点解析

2019年07月24日  | 移动技术网IT编程  | 我要评论

ca1121航班,remaic,造孽才子唐伯虎

问题说明:
当swiperefreshlayout中放置了viewpager控件,两者的滑动会相互冲突.具体表现为viewpager的左右滑动不顺畅,容易被swiperefreshlayout拦截(即出现刷新的view).

问题原因:
viewpager本身是处理了滚动事件的冲突,它在横向滑动时会调用requestdisallowintercepttouchevent()方法使父控件不拦截当前的touch事件序列.但是swiperefreshlayout的requestdisallowintercepttouchevent()方法什么也没有做,所以仍然会拦截当前的touch事件序列.

问题分析:
为什么swiperefreshlayout的requestdisallowintercepttouchevent()方法什么都不做?

首先swiperefreshlayout继承自viewgroup.

在requestdisallowintercepttouchevent()方法什么都不做的情况下,用户可以从底部下拉刷新一次拉出loadingview.
如果方法调用viewgroup的requestdisallowintercepttouchevent()方法, 可以解决viewpager的兼容问题,但是用户在界面底部下拉至头部后,无法继续下拉,需要手指放开一次才能拉出loadingview.
目标分析:
那么为了更加顺滑地滚动,想要的效果当然是一次性拉出loadingview.既然viewpager在左右滑动时才会调用requestdisallowintercepttouchevent()方法,那么swiperefreshlayout只应该在上下滑动时才拦截touch事件.

具体逻辑如下:

记录是否调用了requestdisallowintercepttouchevent()方法,并且设置为true.
在swiperefreshlayout中判断是否是上下滑动.
如果同时满足1,2,则调用super.requestdisallowintercepttouchevent(true).
否则调用super.requestdisallowintercepttouchevent(false).
注意:因为viewgroup的requestdisallowintercepttouchevent方法设置true后,touch事件在dispatchtouchevent()方法中就会被拦截,所以需要在dispatchtouchevent()方法中判断是否为上下滑动.

实现代码(部分):

//非法按键
private static final int invalid_pointer = -1;

//dispatch方法记录第一次按下的x
private float minitialdispatchdownx;

//dispatch方法记录第一次按下的y
private float minitialdispatchdowny;

//dispatch方法记录的手指
private int mactivedispatchpointerid = invalid_pointer;

//是否请求拦截
private boolean hasrequestdisallowintercept = false;

@override
public void requestdisallowintercepttouchevent(boolean b) {
  hasrequestdisallowintercept = b;
  // nope.
}

@override
public boolean dispatchtouchevent(motionevent ev) {
  switch (ev.getaction()) {
    case motionevent.action_down:
      mactivedispatchpointerid = motioneventcompat.getpointerid(ev, 0);
      final float initialdownx = getmotioneventx(ev, mactivedispatchpointerid);
      if (initialdownx != invalid_pointer) {
        minitialdispatchdownx = initialdownx;
      }
      final float initialdowny = getmotioneventy(ev, mactivedispatchpointerid);
      if (minitialdispatchdowny != invalid_pointer) {
        minitialdispatchdowny = initialdowny;
      }
      break;
    case motionevent.action_move:
      if (hasrequestdisallowintercept) {
        //解决viewpager滑动冲突问题
        final float x = getmotioneventx(ev, mactivedispatchpointerid);
        final float y = getmotioneventy(ev, mactivedispatchpointerid);
        if (minitialdispatchdownx != invalid_pointer && x != invalid_pointer &&
            minitialdispatchdowny != invalid_pointer && y != invalid_pointer) {
          final float xdiff = math.abs(x - minitialdispatchdownx);
          final float ydiff = math.abs(y - minitialdispatchdowny);
          if (xdiff > mtouchslop && xdiff * 0.7f > ydiff) {
            //横向滚动不需要拦截
            super.requestdisallowintercepttouchevent(true);
          } else {
            super.requestdisallowintercepttouchevent(false);
          }
        } else {
          super.requestdisallowintercepttouchevent(false);
        }
      }
      break;
    case motionevent.action_up:
    case motionevent.action_cancel:
      if (ev.getaction() == motionevent.action_up || ev.getaction() == motionevent.action_cancel) {
        hasrequestdisallowintercept = false;
      }
      break;
  }

  return super.dispatchtouchevent(ev);
}

private float getmotioneventy(motionevent ev, int activepointerid) {
  final int index = motioneventcompat.findpointerindex(ev, activepointerid);
  if (index < 0) {
    return -1;
  }
  return motioneventcompat.gety(ev, index);
}

private float getmotioneventx(motionevent ev, int activepointerid) {
  final int index = motioneventcompat.findpointerindex(ev, activepointerid);
  if (index < 0) {
    return -1;
  }
  return motioneventcompat.getx(ev, index);
}

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网