开篇
有了我之前的一篇文章做铺垫:仿IOS拖拽回弹之进阶ReboundFrameLayout,本篇特地针对RecyclerView做了一个酷炫的拖拽反弹效果。当然,如果童鞋们想自己实现一个下拉刷新、上拉加载更多的RecyclerView,可以参考本篇的ReboundRecyclerView,在其基础上封装实现。
RecyclerView列表无缝下拉上滑
RecyclerView列表支持平滑fling
释放反弹效果
效果截屏
立即体验
扫描以下二维码下载体验App(从0.2.3版本开始,体验App内嵌版本更新检测功能):
JSCKit库传送门:https://github.com/JustinRoom/JSCKit
简析源码
ReboundRecyclerView.java
初始化视图:
public void init(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
overScroller = new OverScroller(context); final ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
mMinimumVelocity = viewConfiguration.getScaledMinimumFlingVelocity();
mMaximumVelocity = viewConfiguration.getScaledMaximumFlingVelocity();
scaledTouchSlop = viewConfiguration.getScaledTouchSlop();
recyclerView = new RecyclerView(context);
recyclerView.setVerticalScrollBarEnabled(false);
recyclerView.setNestedScrollingEnabled(false);
addView(recyclerView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
}mMinimumVelocity:最小滑动速度mMaximumVelocity:最大滑动速度
是否拦截touch事件:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: //记录是否按下
if (!pressed) {
pressed = true;
} //停止自动滑动
if (!overScroller.isFinished()) {
overScroller.forceFinished(true);
} //停止RecyclerView列表的滑动
recyclerView.stopScroll();
mLastTouchY = ev.getY(); break; case MotionEvent.ACTION_MOVE: float curTouchY = ev.getY(); float deltaY = mLastTouchY - curTouchY;
mLastTouchY = curTouchY; //如果滑动距离小于scaledTouchSlop,则把事件交给子View消耗;否则此事件交由自己的onTouchEvent(MotionEvent event)方法消耗。
if (Math.abs(deltaY) >= scaledTouchSlop) return true; break; case MotionEvent.ACTION_UP:
pressed = false; break;
} return super.onInterceptTouchEvent(ev);
}处理touch事件:
@Override
public boolean onTouchEvent(MotionEvent event) { //跟踪滑动事件,在MotionEvent.ACTION_UP计算滑动速度
trackerEvent(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN:
mLastTouchY = event.getY(); break; case MotionEvent.ACTION_MOVE: float curTouchY = event.getY(); float dy = mLastTouchY - curTouchY; int deltaY = (int) (dy);
mLastTouchY = curTouchY; //执行滑动处理
move(deltaY); break; case MotionEvent.ACTION_UP: //计算滑动速度
int initialVelocity = getYVelocity(); if (Math.abs(initialVelocity) > mMinimumVelocity) { int verticalOffset = recyclerView.computeVerticalScrollOffset(); int distanceFromBottom = recyclerView.computeVerticalScrollRange() - verticalOffset - recyclerView.getMeasuredHeight(); if ((initialVelocity > 0 && verticalOffset > 0)
|| (initialVelocity < 0 && distanceFromBottom > 0)) { //执行RecyclerView平滑
recyclerView.fling(0, -initialVelocity);
}
} //执行反弹
rebound(); //释放滑动事件跟踪器
recycleVelocityTracker(); break;
} return true;
}处理MotionEvent.ACTION_MOVE事件:
/**
*
* @param deltaY negative value represents moving down, positive value represents moving up.
*/
private void move(int deltaY) { int verticalOffset = recyclerView.computeVerticalScrollOffset(); int distanceFromBottom = recyclerView.computeVerticalScrollRange() - verticalOffset - recyclerView.getMeasuredHeight();// Log.i(TAG, "move: scrollY = " + getScrollY());
//getScrollY()<0 子view的顶部向下离开ReboundRecyclerView的顶部;getScrollY()>0 子view的底部向上离开ReboundRecyclerView的底部
int scrollDistance = 0; int scrollY = -getScrollY(); if (deltaY < 0) {//向下滑动
//recyclerView底部已经向上离开ReboundRecyclerView的底部
if (scrollY < 0) {
scrollDistance = Math.max(deltaY, scrollY);
scrollBy(0, (int) (scrollDistance * scrollRatio));
deltaY = deltaY - scrollDistance; if (deltaY >= 0) return;
}
scrollDistance = Math.max(deltaY, -verticalOffset);
recyclerView.scrollBy(0, scrollDistance);
deltaY = deltaY - scrollDistance; if (deltaY >= 0) return;
scrollBy(0, (int) (deltaY * scrollRatio));
} else if (deltaY > 0) {//向上滑动
//recyclerView顶部已经向下离开ReboundRecyclerView的顶部
if (scrollY > 0) {
scrollDistance = Math.min(deltaY, scrollY);
scrollBy(0, (int) (scrollDistance * scrollRatio));
deltaY = deltaY - scrollDistance; if (deltaY <= 0) return;
}
scrollDistance = Math.min(deltaY, distanceFromBottom);
recyclerView.scrollBy(0, scrollDistance);
deltaY = deltaY - scrollDistance; if (deltaY <= 0) return;
scrollBy(0, (int) (deltaY * scrollRatio));
}
}
}执行回弹:
private void rebound() { if (getScrollY() == 0) return;
overScroller.startScroll(0, getScrollY(), 0, -getScrollY(), calculateDurationByScrollY());
invalidate();
}完事!!!
如果想在这个ReboundRecyclerView基础上实现下拉刷新、上拉加载更多功能,请处理move(int deltaY)方法中的deltaY!
作者:JustinRoom
链接:https://www.jianshu.com/p/c3f2c9f852ef
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦

