OverScrollLinearLayoutManager
来源:互联网 发布:南京软件大道租房 编辑:程序博客网 时间:2024/06/06 17:31
这个是一个针对RecyclerView实现的滚动回弹效果,目前仅针对LinearLayoutManager做了拓展。核心代码是:
首先,通过修改LinearLayoutManager的滚动方法scrollVerticallyBy,实现over scroll。
@Override public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { /* scroll before content */ int scrolled = scrollVerticallyBefore(dy, recycler, state); /* scroll content */ scrolled += super.scrollVerticallyBy(dy - scrolled, recycler, state); /* scroll after content */ scrolled += scrollVerticallyAfter(dy - scrolled, recycler, state); /* if still throw {java.lang.IllegalArgumentException: Pixel distance must be non-negative} just disable prefect 0.0 */ //this.setItemPrefetchEnabled(mOverOffsetY == 0); return scrolled; }
然后修改onScrollStateChanged方法,在滚动结束的时候实现回弹效果:
@Override public void onScrollStateChanged(int state) { super.onScrollStateChanged(state); if (state == RecyclerView.SCROLL_STATE_IDLE) { if (mOverScrollY != 0) { this.mRecyclerView.smoothScrollBy(0, -mOverScrollY); } } }
完整代码如下:
/** * Description: extend LinearLayoutManager for over scroll or fling * Author: xuqingqi * E-mail: xuqingqi01@gmail.com * Date: 2017/6/15 */public class LinearLayoutManagerExtend extends LinearLayoutManager { private static final String TAG = LinearLayoutManagerExtend.class.getSimpleName(); private static final int MAX_OVER_SCROLL_DOWN = -128; private static final int MAX_OVER_SCROLL_UP = 128; private RecyclerView mRecyclerView; private int mMaxOverScrollUp; private int mMaxOverScrollDown; private int mOverScrollY; private int mOverOffsetY; private int mOverFactorY = 2; private List<OnOverScrollListener> mOverScrollListeners; private boolean mOnFling = false; public LinearLayoutManagerExtend(RecyclerView recyclerView, int orientation, boolean reverseLayout) { super(recyclerView.getContext(), orientation, reverseLayout); this.mRecyclerView = recyclerView; this.mRecyclerView.setOverScrollMode(RecyclerView.OVER_SCROLL_NEVER); float density = recyclerView.getContext().getResources().getDisplayMetrics().density; this.mMaxOverScrollDown = (int) (MAX_OVER_SCROLL_DOWN * density * mOverFactorY); this.mMaxOverScrollUp = (int) (MAX_OVER_SCROLL_UP * density * mOverFactorY); } @Override public void collectAdjacentPrefetchPositions(int dx, int dy, RecyclerView.State state, LayoutPrefetchRegistry layoutPrefetchRegistry) { if (mOverScrollY != 0) { // TODO ugly bug fix. should not happen return; } try { super.collectAdjacentPrefetchPositions(dx, dy, state, layoutPrefetchRegistry); } catch (IllegalArgumentException iae) { iae.printStackTrace(); // TODO fix me, still throw #IllegalArgumentException: Pixel distance must be non-negative } } @Override public void collectInitialPrefetchPositions(int adapterItemCount, LayoutPrefetchRegistry layoutPrefetchRegistry) { if (mOverScrollY != 0) { // TODO ugly bug fix. should not happen return; } super.collectInitialPrefetchPositions(adapterItemCount, layoutPrefetchRegistry); } @Override public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { /* scroll before content */ int scrolled = scrollVerticallyBefore(dy, recycler, state); /* scroll content */ scrolled += super.scrollVerticallyBy(dy - scrolled, recycler, state); /* scroll after content */ scrolled += scrollVerticallyAfter(dy - scrolled, recycler, state); /* if still throw {java.lang.IllegalArgumentException: Pixel distance must be non-negative} just disable prefect 0.0 */ //this.setItemPrefetchEnabled(mOverOffsetY == 0); return scrolled; } @Override public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { return super.scrollHorizontallyBy(dx, recycler, state); } @SuppressWarnings("unused") private int scrollVerticallyBefore(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { if (getOrientation() == HORIZONTAL || dy == 0) { return 0; } int consumed = 0; if (dy > 0 && mOverScrollY < 0) { /* scroll up */ consumed = dy + mOverScrollY > 0? -mOverScrollY : dy; } else if (dy < 0 && mOverScrollY > 0) { /* scroll down */ consumed = dy + mOverScrollY < 0? -mOverScrollY : dy; } if (consumed != 0) { mOverScrollY += consumed; int offset = mOverScrollY / mOverFactorY - mOverOffsetY; offsetChildrenVertical(-offset); mOverOffsetY += offset; /* mOverOffsetY equals (int) (mOverScrollY * mOverFactorY) */ dispatchOverScrolled(consumed, offset); Looger.I(this, "over scrolled before by " + consumed); } return consumed; } @SuppressWarnings("unused") private int scrollVerticallyAfter(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { if (getOrientation() == HORIZONTAL || dy == 0) { return 0; } int consumed = 0; if (dy > 0) { /* scroll up */ consumed = dy + mOverScrollY > mMaxOverScrollUp? mMaxOverScrollUp - mOverScrollY : dy; } else if (dy < 0) { /* scroll down */ consumed = dy + mOverScrollY < mMaxOverScrollDown? mMaxOverScrollDown - mOverScrollY : dy; } if (consumed != 0) { mOverScrollY += consumed; int offset = mOverScrollY / mOverFactorY - mOverOffsetY; offsetChildrenVertical(-offset); mOverOffsetY += offset; /* mOverOffsetY equals {mOverScrollY / mOverFactorY} */ dispatchOverScrolled(consumed, offset); Looger.I(this, "over scrolled after by " + consumed); } return consumed; } @Override public void onScrollStateChanged(int state) { super.onScrollStateChanged(state); if (state == RecyclerView.SCROLL_STATE_IDLE) { if (mOverScrollY != 0) { this.mRecyclerView.smoothScrollBy(0, -mOverScrollY); } } } @SuppressWarnings("unused") private Context getContext() { return this.mRecyclerView.getContext(); } @Override public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state){ super.onLayoutChildren(recycler, state); } @Override public void onLayoutCompleted(RecyclerView.State state) { super.onLayoutCompleted(state); updateLayoutState(); } private void updateLayoutState() { mOverScrollY = 0; mOverOffsetY = 0; dispatchStateUpdated(); } @Override public void onAttachedToWindow(RecyclerView view) { updateLayoutState(); super.onAttachedToWindow(view); } @Override public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) { super.onDetachedFromWindow(view, recycler); updateLayoutState(); } public void addOverScroll(OnOverScrollListener listener) { if (listener == null) { return; } if (mOverScrollListeners == null) { mOverScrollListeners = new ArrayList<>(); } if (mOverScrollListeners.contains(listener)) { return; } mOverScrollListeners.add(listener); } public void removeOverScroll(OnOverScrollListener listener) { if (listener == null) { return; } if (mOverScrollListeners == null) { return; } mOverScrollListeners.remove(listener); } private void dispatchOverScrolled(int dScroll, int dOffset) { if (mOverScrollListeners == null) { return; } for (int i = 0; i < mOverScrollListeners.size(); i++) { OnOverScrollListener listener = mOverScrollListeners.get(i); listener.onOverScrolled(mRecyclerView, mOverScrollY, mOverOffsetY, dScroll, dOffset); } } private void dispatchStateUpdated() { if (mOverScrollListeners == null) { return; } for (int i = 0; i < mOverScrollListeners.size(); i++) { OnOverScrollListener listener = mOverScrollListeners.get(i); listener.onStateUpdated(mRecyclerView, mOverScrollY, mOverOffsetY); } } public void onFling(int velocityX, int velocityY) { mOnFling = true; }}
阅读全文
0 0
- OverScrollLinearLayoutManager
- java一个最简单的反射的例子
- 2017.12.6-2017.12.19 学习情况
- Emmet的简单使用
- mysql命令
- 查询本日、本周、本月的数据
- OverScrollLinearLayoutManager
- 魅族MX5——视频播放,横竖屏切换黑屏,有声音没图像
- 详细:Liunx中配置java环境变量以及tomcat环境变量
- 在桌面右键菜单添加【切换电源计划】选项
- 解决Eclipse SVN文件冲突
- spring--AOP基本概念及特点
- 《Java编程技巧1001条》第364条 0为基的对象
- PHP中Trait详解及其应用
- excel文件到导入到数据库,date类型的处理