Android – RecyclerView.scrollDurch Quellcode-Analyse

In letzter Zeit besteht die Anforderung, dass beim Scrollen von RecyclerView nach links und rechts die Fokusansicht in die Mitte des Bildschirms gerollt wird, wenn die Fokusansicht die Mitte des Bildschirms überschreitet. Die Implementierungsidee besteht darin, die Koordinaten der Fokusansicht auf dem Bildschirm zu ermitteln und die Bildlaufentfernung entsprechend der Bildschirmbreite/2 zu berechnen. Code wie folgt anzeigen:

FocusLinearLayoutManager layoutManager = (FocusLinearLayoutManager) provincesList.getLayoutManager();
int firstVisiblePos = layoutManager.findFirstVisibleItemPosition();
View view = provincesList.getChildAt(position - firstVisiblePos);
int[] location = new int[2];
view.getLocationOnScreen(location);
int half_width = DensityUtil.getScreenWidth(this) / 2;
provincesList.scrollBy(location[0] - half_width, 0);

Das heute zu analysierende Problem besteht nicht darin, die oben genannten Anforderungen zu erfüllen, sondern darin, wie scrollBy implementiert werden kann.
scrollBy wird in der scrollByInternal-Methode ausgeführt. Das Folgende ist ein Code für scrollByInternal.

 int unconsumedX = 0, unconsumedY = 0;
        int consumedX = 0, consumedY = 0;

        consumePendingUpdateOperations();
        if (mAdapter != null) {
            eatRequestLayout();
            onEnterLayoutOrScroll();
            TraceCompat.beginSection(TRACE_SCROLL_TAG);
            fillRemainingScrollValues(mState);
            if (x != 0) {
                consumedX = mLayout.scrollHorizontallyBy(x, mRecycler, mState);
                unconsumedX = x - consumedX;
            }
            if (y != 0) {
                consumedY = mLayout.scrollVerticallyBy(y, mRecycler, mState);
                unconsumedY = y - consumedY;
            }
            TraceCompat.endSection();
            repositionShadowingViews();
            onExitLayoutOrScroll();
            resumeRequestLayout(false);
        }

Es mLayout.scrollHorizontallyBy(x, mRecycler, mState);ist ersichtlich, dass RecyclerView das Scrollen an Layoutmanager übergeben hat, und wir werden dies weiterhin verfolgen. (Hier nehmen wir horizontales Scrollen als Beispiel)

LinearlayoutManager.scrollHorizontalBy:

    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
            RecyclerView.State state) {
        if (mOrientation == VERTICAL) {
            return 0;
        }
        return scrollBy(dx, recycler, state);
    }

int scrollBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
        if (getChildCount() == 0 || dy == 0) {
            return 0;
        }
        mLayoutState.mRecycle = true;
        ensureLayoutState();
        final int layoutDirection = dy > 0 ? LayoutState.LAYOUT_END : LayoutState.LAYOUT_START;
        final int absDy = Math.abs(dy);
        updateLayoutState(layoutDirection, absDy, true, state);
        final int consumed = mLayoutState.mScrollingOffset
                + fill(recycler, mLayoutState, state, false);
        if (consumed < 0) {
            if (DEBUG) {
                Log.d(TAG, "Don't have any more elements to scroll");
            }
            return 0;
        }
        final int scrolled = absDy > consumed ? layoutDirection * consumed : dy;
        mOrientationHelper.offsetChildren(-scrolled);
        if (DEBUG) {
            Log.d(TAG, "scroll req: " + dy + " scrolled: " + scrolled);
        }
        mLayoutState.mLastScrollDelta = scrolled;
        return scrolled;
    }

Die scrollBy-Methode mOrientationHelper.offsetChildren(-scrolled);gibt an, dass die Ansicht als nächstes verschoben wird.

public void offsetChildren(int amount) {
	mLayoutManager.offsetChildrenHorizontal(amount);
}

Wie aus dem obigen Code ersichtlich ist, kehrt die Ausführung des endgültigen Codes zum Layoutmanager zurück.

public void offsetChildrenHorizontal(int dx) {
       if (mRecyclerView != null) {
             mRecyclerView.offsetChildrenHorizontal(dx);
        }
}

public void offsetChildrenHorizontal(int dx) {
        final int childCount = mChildHelper.getChildCount();
        for (int i = 0; i < childCount; i++) {
            mChildHelper.getChildAt(i).offsetLeftAndRight(dx);
        }
}

Schlagen Sie hier an die Tafel! ! ! Ich möchte es wirklich klarstellen und bin schließlich zur Ansicht zurückgekehrt, um mich damit zu befassen

   public void offsetLeftAndRight(int offset) {
        if (offset != 0) {
            final boolean matrixIsIdentity = hasIdentityMatrix();
            if (matrixIsIdentity) {
                if (isHardwareAccelerated()) {
                    invalidateViewProperty(false, false);
                } else {
                    final ViewParent p = mParent;
                    if (p != null && mAttachInfo != null) {
                        final Rect r = mAttachInfo.mTmpInvalRect;
                        int minLeft;
                        int maxRight;
                        if (offset < 0) {
                            minLeft = mLeft + offset;
                            maxRight = mRight;
                        } else {
                            minLeft = mLeft;
                            maxRight = mRight + offset;
                        }
                        r.set(0, 0, maxRight - minLeft, mBottom - mTop);
                        p.invalidateChild(this, r);
                    }
                }
            } else {
                invalidateViewProperty(false, false);
            }
        }
    }

Die wichtigsten davon sind diese Zeilen, die die Koordinaten der Ansicht neu berechnen.

 if (offset < 0) {
	minLeft = mLeft + offset;
    maxRight = mRight;
} else {
    minLeft = mLeft;
    maxRight = mRight + offset;
}

Vor diesem Hintergrund ist es nicht erforderlich, am Anfang des Artikels zu erklären, wie RecyclerView die Scrollentfernung berechnet. Scrollen Sie nach links, um die X-Koordinate nach links zu verschieben, und scrollen Sie nach rechts, um die X-Koordinate nach rechts zu verschieben.

Die Analyse ist nicht sehr detailliert und dient hauptsächlich der Klärung des Prozesses und dem Verständnis des Prinzips.

Guess you like

Origin blog.csdn.net/u012230055/article/details/106409360