public class FollowScrollListener extends RecyclerView.OnScrollListener { private int MAX_DISTANCE = DPIUtil.getWidthByDesignValue720(406) + 500; private View followScrollView; private int preDistance; private SparseIntArray dValues = new SparseIntArray(); private int totalDy; public FollowScrollListener(View followScrollView) { this.followScrollView = followScrollView; } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { int distance = Math.max(- MAX_DISTANCE, Math.min(0, getMovedDistance(recyclerView, dy))); if (preDistance == distance) return; preDistance = distance; if (followScrollView != null) { followScrollView.setTranslationY(distance); } } /** * 解决rv在滑动时item动态变动导致计算滚动总距离有误差的坑: * a)上滑时记录各楼层itemView的top位置 * b) 正常情况下滑动距离与楼层top的差值是不变的。 * c) 所以下滑时通过(top + 差值)校验获取正确总滚动距离 * d) 在滑到顶部时清除记录 * @param recyclerView * @param dy * @return */ private int getMovedDistance(RecyclerView recyclerView, int dy) { totalDy -= dy; LinearLayoutManager lm = (LinearLayoutManager) recyclerView.getLayoutManager(); int position = lm.findFirstVisibleItemPosition(); View view = lm.findViewByPosition(position); if (view == null) return totalDy; int top = view.getTop(); if (dValues.indexOfKey(position) < 0) { dValues.put(position, totalDy - top); // a } else { totalDy = dValues.get(position) + top; // c } if (Log.D) { Log.d("FollowScrollListener", "onScrolled: dy = " + dy + ", totalDy = " + totalDy); } if (totalDy == 0) { dValues.clear(); // d if (Log.D) { Log.d("FollowScrollListener", "getMovedDistance: dValues cleared"); } } return totalDy; } }
跟随RecyclerView滚动的算法
最新推荐文章于 2022-11-17 16:38:53 发布