snaphelper

先写引用 侵删
https://www.jianshu.com/p/e54db232df62
https://www.jianshu.com/p/9b8e0696802d


/**
 * Created by Administrator (chenPS) on 2020/3/4.
 */
public class LeftSnapHelper extends SnapHelper {
    // Orientation helpers are lazily created per LayoutManager.
    @Nullable
    private OrientationHelper mVerticalHelper;
    @Nullable
    private OrientationHelper mHorizontalHelper;


    @Nullable
    @Override
    public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView) {
        Log.w("LeftSnapHelper", "calculateDistanceToFinalSnap");
        int out[] = new int[2];
        if (layoutManager.canScrollHorizontally()) {
            out[0] = distanceToEnd(targetView, getHorizontalHelper(layoutManager));
        } else {
            out[0] = 0;
        }

        return out;
    }

    //targetView的start坐标与RecyclerView的paddingStart之间的差值
    //就是需要滚动调整的距离
    private int distanceToStart(View targetView, OrientationHelper helper) {
        return helper.getDecoratedStart(targetView) - helper.getStartAfterPadding();
    }

    private int distanceToEnd(View targetView, OrientationHelper helper) {
        Log.v("test",helper.getEndAfterPadding()+"      ===      "+helper.getDecoratedEnd(targetView));
        return -helper.getEndAfterPadding() + helper.getDecoratedEnd(targetView);
    }


    /**
     * 该方法会找到当前layoutManager上最接近对齐位置的那个view,
     * 该view称为SanpView,对应的position称为SnapPosition。
     * 如果返回null,就表示没有需要对齐的View,也就不会做滚动对齐调整。
     */
    @Nullable
    @Override
    public View findSnapView(RecyclerView.LayoutManager layoutManager) {
        Log.w("LeftSnapHelper", "findSnapView");

        return findEndView(layoutManager, getHorizontalHelper(layoutManager));
    }


    private View findEndView(RecyclerView.LayoutManager layoutManager, OrientationHelper helper) {
        if (!layoutManager.canScrollHorizontally()) {
            return null;
        }
        if (layoutManager instanceof LinearLayoutManager) {
            int lastItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
            View view = layoutManager.findViewByPosition(lastItemPosition);
            if(view==null){
                return null;
            }
            int itemWidth = helper.getDecoratedMeasurement(view)/2;
            Log.v("test",itemWidth+"    item 的宽度");
            int invisiableWidth =helper.getDecoratedEnd(view)-helper.getEnd();
            Log.v("test",invisiableWidth+"     ");
            if (invisiableWidth < itemWidth) {
                return view;
            } else {
                return layoutManager.findViewByPosition(lastItemPosition - 1);
            }
        }
        return null;

    }


    private View findStartView(RecyclerView.LayoutManager layoutManager, OrientationHelper helper) {
        if (layoutManager instanceof LinearLayoutManager) {
            int firstChildPosition = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition();
            if (firstChildPosition == RecyclerView.NO_POSITION) {
                return null;
            }
            //找到最后一个完全显示的ItemView,如果该ItemView是列表中的最后一个
            //就说明列表已经滑动最后了,这时候就不应该根据第一个ItemView来对齐了
            //要不然由于需要跟第一个ItemView对齐最后一个ItemView可能就一直无法完全显示,
            //所以这时候直接返回null表示不需要对齐
            if (((LinearLayoutManager) layoutManager).findLastCompletelyVisibleItemPosition() == layoutManager.getItemCount() - 1) {
                return null;
            }
            View firstChildView = layoutManager.findViewByPosition(firstChildPosition);
            if (helper.getDecoratedEnd(firstChildView) >= helper.getDecoratedMeasurement(firstChildView) / 2
                    && helper.getDecoratedEnd(firstChildView) > 0) {
                return firstChildView;
            } else {
                return layoutManager.findViewByPosition(firstChildPosition + 1);
            }
        } else {
            return null;
        }
    }


    //在触发fling时找到targetSnapPosition。
    @Override
    public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {
        Log.e("LeftSnapHelper", "findTargetSnapPosition");

        if (!(layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider)) {
            return -1;
        }
        int itemCount = layoutManager.getItemCount();
        if (itemCount == 0) {
            return -1;
        }
        View currentView = findSnapView(layoutManager);
        if (currentView == null) {
            return -1;
        }

        int currentPosition = layoutManager.getPosition(currentView);
        if (currentPosition == -1) {
            return -1;
        }
        RecyclerView.SmoothScroller.ScrollVectorProvider vectorProvider = (RecyclerView.SmoothScroller.ScrollVectorProvider) layoutManager;
        PointF vectorForEnd = vectorProvider.computeScrollVectorForPosition(itemCount - 1);
        if (vectorForEnd == null) {
            return -1;
        }
        int deltaThreshold = layoutManager.getWidth() / getHorizontalHelper(layoutManager).getDecoratedMeasurement(currentView);

        int deltaJump;
        if (layoutManager.canScrollHorizontally()) {
            deltaJump = estimateNextPositionDiffForFling(layoutManager, getHorizontalHelper(layoutManager), velocityX, 0);
            if (deltaJump > deltaThreshold) {
                deltaJump = deltaThreshold;
            }
            if (deltaJump < -deltaThreshold) {
                deltaJump = -deltaThreshold;
            }

            if (vectorForEnd.x < 0) {
                deltaJump = -deltaJump;
            }
        } else {
            deltaJump = 0;
        }
        if (deltaJump == 0) {
            return -1;
        }
        int targetPos = currentPosition + deltaJump;
        if (targetPos < 0) {
            targetPos = 0;
        }
        if (targetPos >= itemCount) {
            targetPos = itemCount - 1;
        }

        return targetPos;
    }


    @NonNull
    private OrientationHelper getVerticalHelper(@NonNull RecyclerView.LayoutManager layoutManager) {
        if (mVerticalHelper == null) {
            mVerticalHelper = OrientationHelper.createVerticalHelper(layoutManager);
        }
        return mVerticalHelper;
    }

    @NonNull
    private OrientationHelper getHorizontalHelper(
            @NonNull RecyclerView.LayoutManager layoutManager) {
        if (mHorizontalHelper == null) {
            mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager);
        }
        return mHorizontalHelper;
    }

    private int estimateNextPositionDiffForFling(RecyclerView.LayoutManager layoutManager,
                                                 OrientationHelper helper, int velocityX, int velocityY) {
        int[] distances = calculateScrollDistance(velocityX, velocityY);
        float distancePerChild = computeDistancePerChild(layoutManager, helper);
        if (distancePerChild <= 0) {
            return 0;
        }
        int distance =
                Math.abs(distances[0]) > Math.abs(distances[1]) ? distances[0] : distances[1];
        return (int) Math.round(distance / distancePerChild);
    }

    private float computeDistancePerChild(RecyclerView.LayoutManager layoutManager,
                                          OrientationHelper helper) {
        View minPosView = null;
        View maxPosView = null;
        int minPos = Integer.MAX_VALUE;
        int maxPos = Integer.MIN_VALUE;
        int childCount = layoutManager.getChildCount();
        if (childCount == 0) {
            return 1f;
        }

        for (int i = 0; i < childCount; i++) {
            View child = layoutManager.getChildAt(i);
            final int pos = layoutManager.getPosition(child);
            if (pos == RecyclerView.NO_POSITION) {
                continue;
            }
            if (pos < minPos) {
                minPos = pos;
                minPosView = child;
            }
            if (pos > maxPos) {
                maxPos = pos;
                maxPosView = child;
            }
        }
        if (minPosView == null || maxPosView == null) {
            return 1f;
        }
        int start = Math.min(helper.getDecoratedStart(minPosView),
                helper.getDecoratedStart(maxPosView));
        int end = Math.max(helper.getDecoratedEnd(minPosView),
                helper.getDecoratedEnd(maxPosView));
        int distance = end - start;
        if (distance == 0) {
            return 1f;
        }
        return 1f * distance / ((maxPos - minPos) + 1);
    }

    @Nullable
    @Override
    protected LinearSmoothScroller createSnapScroller(RecyclerView.LayoutManager layoutManager) {

        return super.createSnapScroller(layoutManager);
    }
}

你可能感兴趣的:(snaphelper)