Android 酷炫拖拽反弹ReboundRecyclerVie
2018-07-06 本文已影响44人
SwitchLife
开篇
有了我之前的一篇文章做铺垫:仿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
!
篇尾!
QQ:1006368252
、WeChat:eoy9527
学到很多东西的诀窍,就是一下子不要学很多。——洛克