开篇
有了我之前的一篇文章做铺垫:仿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