Android中ViewPager带来的滑动卡顿问题解决要点解析
问题说明:
当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); }
上一篇: 扒一扒 Java 中的枚举类型
下一篇: java获取日期之间天数的方法