car/src/main/java/androidx/car/widget/PagedSnapHelper.java
@Override
    @Nullable
    public View findSnapView(RecyclerView.LayoutManager layoutManager) {
        int childCount = layoutManager.getChildCount();
        if (childCount == 0) {
            return null;
        }

        OrientationHelper orientationHelper = getOrientationHelper(layoutManager);

        // If there's only one child, then that will be the snap target.
        if (childCount == 1) {
            View firstChild = layoutManager.getChildAt(0);
            return isValidSnapView(firstChild, orientationHelper) ? firstChild : null;
        }

        // If the top child view is longer than the RecyclerView (long item), and it's not yet
        // scrolled out - meaning the screen it takes up is more than threshold,
        // do not snap to any view.
        // This way avoids next View snapping to top "pushes" out the end of a long item.
        View firstChild = mRecyclerView.getChildAt(0);
        if (firstChild.getHeight() > mRecyclerView.getHeight()
                // Long item start is scrolled past screen;
                && orientationHelper.getDecoratedStart(firstChild) < 0
                // and it takes up more than threshold screen size.
                && orientationHelper.getDecoratedEnd(firstChild) > (
                        mRecyclerView.getHeight() * LONG_ITEM_END_VISIBLE_THRESHOLD)) {
            return null;
        }

        View lastVisibleChild = layoutManager.getChildAt(childCount - 1);

        // Check if the last child visible is the last item in the list.
        boolean lastItemVisible =
                layoutManager.getPosition(lastVisibleChild) == layoutManager.getItemCount() - 1;

        // If it is, then check how much of that view is visible.
        float lastItemPercentageVisible = lastItemVisible
                ? getPercentageVisible(lastVisibleChild, orientationHelper) : 0;

        View closestChild = null;
        int closestDistanceToStart = Integer.MAX_VALUE;
        float closestPercentageVisible = 0.f;

        // Iterate to find the child closest to the top and more than half way visible.
        for (int i = 0; i < childCount; i++) {
            View child = layoutManager.getChildAt(i);
            int startOffset = orientationHelper.getDecoratedStart(child);

            if (Math.abs(startOffset) < closestDistanceToStart) {
                float percentageVisible = getPercentageVisible(child, orientationHelper);

                if (percentageVisible > VIEW_VISIBLE_THRESHOLD
                        && percentageVisible > closestPercentageVisible) {
                    closestDistanceToStart = startOffset;
                    closestChild = child;
                    closestPercentageVisible = percentageVisible;
                }
            }
        }

        View childToReturn = closestChild;

        // If closestChild is null, then that means we were unable to find a closest child that
        // is over the VIEW_VISIBLE_THRESHOLD. This could happen if the views are larger than
        // the given area. In this case, consider returning the lastVisibleChild so that the screen
        // scrolls. Also, check if the last item should be displayed anyway if it is mostly visible.
        if ((childToReturn == null
                || (lastItemVisible && lastItemPercentageVisible > closestPercentageVisible))) {
            childToReturn = lastVisibleChild;
        }

        // Return null if the childToReturn is not valid. This allows the user to scroll freely
        // with no snapping. This can allow them to see the entire view.
        return isValidSnapView(childToReturn, orientationHelper) ? childToReturn : null;
    }
/**
     * Finds the view to snap to. The view to snap to is the child of the LayoutManager that is
     * closest to the start of the RecyclerView. The "start" depends on if the LayoutManager
     * is scrolling horizontally or vertically. If it is horizontally scrolling, then the
     * start is the view on the left (right if RTL). Otherwise, it is the top-most view.
     *
     * @param layoutManager The current {@link RecyclerView.LayoutManager} for the attached
     *                      RecyclerView.
     * @return The View closest to the start of the RecyclerView. Returns {@code null}when:
     * <ul>
     *     <li>there is no item; or
     *     <li>no visible item can fully fit in the containing RecyclerView; or
     *     <li>an item longer than containing RecyclerView is about to scroll out.
     * </ul>
     */
Finds the view to snap to. The view to snap to is the child of the LayoutManager that is
closest to the start of the RecyclerView. The "start" depends on if the LayoutManager
is scrolling horizontally or vertically. If it is horizontally scrolling, then the
start is the view on the left (right if RTL). Otherwise, it is the top-most view.


Finds the view to snap to . The view to snap to is the child of the LayoutManager that is closest to the start of the RecyclerView . The " start " depends on if the LayoutManager is scrolling horizontally or vertically . If it is horizontally scrolling then the start is the view on the left ( right if RTL ) . Otherwise it is the top - most view .
@Override
    @Nullable
    public View findSnapView(RecyclerView.LayoutManager layoutManager) {
        int childCount = layoutManager.getChildCount();
        if (childCount == 0) {
            return null;
        }
        OrientationHelper orientationHelper = getOrientationHelper(layoutManager);
        if (childCount == 1) {
            View firstChild = layoutManager.getChildAt(0);
            return isValidSnapView(firstChild, orientationHelper) ? firstChild : null;
        }
        View firstChild = mRecyclerView.getChildAt(0);
        if (firstChild.getHeight() > mRecyclerView.getHeight()
                && orientationHelper.getDecoratedStart(firstChild) < 0
                && orientationHelper.getDecoratedEnd(firstChild) > (
                        mRecyclerView.getHeight() * LONG_ITEM_END_VISIBLE_THRESHOLD)) {
            return null;
        }
        View lastVisibleChild = layoutManager.getChildAt(childCount - 1);
        boolean lastItemVisible =
                layoutManager.getPosition(lastVisibleChild) == layoutManager.getItemCount() - 1;
        float lastItemPercentageVisible = lastItemVisible
                ? getPercentageVisible(lastVisibleChild, orientationHelper) : 0;
        View closestChild = null;
        int closestDistanceToStart = Integer.MAX_VALUE;
        float closestPercentageVisible = 0.f;
        for (int i = 0; i < childCount; i++) {
            View child = layoutManager.getChildAt(i);
            int startOffset = orientationHelper.getDecoratedStart(child);
            if (Math.abs(startOffset) < closestDistanceToStart) {
                float percentageVisible = getPercentageVisible(child, orientationHelper);
                if (percentageVisible > VIEW_VISIBLE_THRESHOLD
                        && percentageVisible > closestPercentageVisible) {
                    closestDistanceToStart = startOffset;
                    closestChild = child;
                    closestPercentageVisible = percentageVisible;
                }
            }
        }
        View childToReturn = closestChild;
        if ((childToReturn == null
                || (lastItemVisible && lastItemPercentageVisible > closestPercentageVisible))) {
            childToReturn = lastVisibleChild;
        }
        return isValidSnapView(childToReturn, orientationHelper) ? childToReturn : null;
    }
@ Override @ Nullable public View findSnapView ( RecyclerView . LayoutManager layoutManager ) { int childCount = layoutManager . getChildCount ( ) ; if ( childCount == 0 ) { return null ; } OrientationHelper orientationHelper = getOrientationHelper ( layoutManager ) ; if ( childCount == 1 ) { View firstChild = layoutManager . getChildAt ( 0 ) ; return isValidSnapView ( firstChild , orientationHelper ) ? firstChild : null ; } View firstChild = mRecyclerView . getChildAt ( 0 ) ; if ( firstChild . getHeight ( ) > mRecyclerView . getHeight ( ) && orientationHelper . getDecoratedStart ( firstChild ) < 0 && orientationHelper . getDecoratedEnd ( firstChild ) > ( mRecyclerView . getHeight ( ) * LONG_ITEM_END_VISIBLE_THRESHOLD ) ) { return null ; } View lastVisibleChild = layoutManager . getChildAt ( childCount - 1 ) ; boolean lastItemVisible = layoutManager . getPosition ( lastVisibleChild ) == layoutManager . getItemCount ( ) - 1 ; float lastItemPercentageVisible = lastItemVisible ? getPercentageVisible ( lastVisibleChild , orientationHelper ) : 0 ; View closestChild = null ; int closestDistanceToStart = Integer . MAX_VALUE ; float closestPercentageVisible = 0.f ; for ( int i = 0 ; i < childCount ; i ++ ) { View child = layoutManager . getChildAt ( i ) ; int startOffset = orientationHelper . getDecoratedStart ( child ) ; if ( Math . abs ( startOffset ) < closestDistanceToStart ) { float percentageVisible = getPercentageVisible ( child , orientationHelper ) ; if ( percentageVisible > VIEW_VISIBLE_THRESHOLD && percentageVisible > closestPercentageVisible ) { closestDistanceToStart = startOffset ; closestChild = child ; closestPercentageVisible = percentageVisible ; } } } View childToReturn = closestChild ; if ( ( childToReturn == null || ( lastItemVisible && lastItemPercentageVisible > closestPercentageVisible ) ) ) { childToReturn = lastVisibleChild ; } return isValidSnapView ( childToReturn , orientationHelper ) ? childToReturn : null ; }
Finds the view to snap to.
Finds the view to snap to .
// If there's only one child, then that will be the snap target. // If the top child view is longer than the RecyclerView (long item), and it's not yet // scrolled out - meaning the screen it takes up is more than threshold, // do not snap to any view. // This way avoids next View snapping to top "pushes" out the end of a long item. // Long item start is scrolled past screen; // and it takes up more than threshold screen size. // Check if the last child visible is the last item in the list. // If it is, then check how much of that view is visible. // Iterate to find the child closest to the top and more than half way visible. // If closestChild is null, then that means we were unable to find a closest child that // is over the VIEW_VISIBLE_THRESHOLD. This could happen if the views are larger than // the given area. In this case, consider returning the lastVisibleChild so that the screen // scrolls. Also, check if the last item should be displayed anyway if it is mostly visible. // Return null if the childToReturn is not valid. This allows the user to scroll freely // with no snapping. This can allow them to see the entire view.