docs: @Override
      public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
  
          // layout algorithm:
          // 1) by checking children and other variables, find an anchor coordinate and an anchor
          //  item position.
          // 2) fill towards start, stacking from bottom
          // 3) fill towards end, stacking from top
          // 4) scroll to fulfill requirements like stack from bottom.
          // create layout state
          if (DEBUG) {
              Log.d(TAG, "is pre layout:" + state.isPreLayout());
          }
          if (mCurrentPendingSavedState != null && mCurrentPendingSavedState.getInt("AnchorPosition") >= 0) {
              mCurrentPendingScrollPosition = mCurrentPendingSavedState.getInt("AnchorPosition");
          }
  
          ensureLayoutStateExpose();
          mLayoutState.mRecycle = false;
          // resolve layout direction
          myResolveShouldLayoutReverse();
  
          mAnchorInfo.reset();
          mAnchorInfo.mLayoutFromEnd = mShouldReverseLayoutExpose ^ getStackFromEnd();
          // calculate anchor position and coordinate
          updateAnchorInfoForLayoutExpose(state, mAnchorInfo);
  
  
          if (DEBUG) {
              Log.d(TAG, "Anchor info:" + mAnchorInfo);
          }
  
          // LLM may decide to layout items for "extra" pixels to account for scrolling target,
          // caching or predictive animations.
          int extraForStart;
          int extraForEnd;
          final int extra = getExtraLayoutSpace(state);
          boolean before = state.getTargetScrollPosition() < mAnchorInfo.mPosition;
          if (before == mShouldReverseLayoutExpose) {
              extraForEnd = extra;
              extraForStart = 0;
          } else {
              extraForStart = extra;
              extraForEnd = 0;
          }
          extraForStart += mOrientationHelper.getStartAfterPadding();
          extraForEnd += mOrientationHelper.getEndPadding();
          if (state.isPreLayout() && mCurrentPendingScrollPosition != RecyclerView.NO_POSITION &&
                  mPendingScrollPositionOffset != INVALID_OFFSET) {
              // if the child is visible and we are going to move it around, we should layout
              // extra items in the opposite direction to make sure new items animate nicely
              // instead of just fading in
              final View existing = findViewByPosition(mCurrentPendingScrollPosition);
              if (existing != null) {
                  final int current;
                  final int upcomingOffset;
                  if (mShouldReverseLayoutExpose) {
                      current = mOrientationHelper.getEndAfterPadding() -
                              mOrientationHelper.getDecoratedEnd(existing);
                      upcomingOffset = current - mPendingScrollPositionOffset;
                  } else {
                      current = mOrientationHelper.getDecoratedStart(existing)
                              - mOrientationHelper.getStartAfterPadding();
                      upcomingOffset = mPendingScrollPositionOffset - current;
                  }
                  if (upcomingOffset > 0) {
                      extraForStart += upcomingOffset;
                  } else {
                      extraForEnd -= upcomingOffset;
                  }
              }
          }
          int startOffset;
          int endOffset;
          onAnchorReady(state, mAnchorInfo);
          detachAndScrapAttachedViews(recycler);
          mLayoutState.mIsPreLayout = state.isPreLayout();
          mLayoutState.mOnRefresLayout = true;
          if (mAnchorInfo.mLayoutFromEnd) {
              // fill towards start
              updateLayoutStateToFillStartExpose(mAnchorInfo);
              mLayoutState.mExtra = extraForStart;
              fill(recycler, mLayoutState, state, false);
              startOffset = mLayoutState.mOffset;
              if (mLayoutState.mAvailable > 0) {
                  extraForEnd += mLayoutState.mAvailable;
              }
              // fill towards end
              updateLayoutStateToFillEndExpose(mAnchorInfo);
              mLayoutState.mExtra = extraForEnd;
              mLayoutState.mCurrentPosition += mLayoutState.mItemDirection;
              fill(recycler, mLayoutState, state, false);
              endOffset = mLayoutState.mOffset;
          } else {
              // fill towards end
              updateLayoutStateToFillEndExpose(mAnchorInfo);
              mLayoutState.mExtra = extraForEnd;
              fill(recycler, mLayoutState, state, false);
              endOffset = mLayoutState.mOffset;
              if (mLayoutState.mAvailable > 0) {
                  extraForStart += mLayoutState.mAvailable;
              }
              // fill towards start
              updateLayoutStateToFillStartExpose(mAnchorInfo);
              mLayoutState.mExtra = extraForStart;
              mLayoutState.mCurrentPosition += mLayoutState.mItemDirection;
              fill(recycler, mLayoutState, state, false);
              startOffset = mLayoutState.mOffset;
          }
  
          // changes may cause gaps on the UI, try to fix them.
          // TODO we can probably avoid this if neither stackFromEnd/reverseLayout/RTL values have
          // changed
          if (getChildCount() > 0) {
              // because layout from end may be changed by scroll to position
              // we re-calculate it.
              // find which side we should check for gaps.
              if (mShouldReverseLayoutExpose ^ getStackFromEnd()) {
                  int fixOffset = fixLayoutEndGapExpose(endOffset, recycler, state, true);
                  startOffset += fixOffset;
                  endOffset += fixOffset;
                  fixOffset = fixLayoutStartGapExpose(startOffset, recycler, state, false);
                  startOffset += fixOffset;
                  endOffset += fixOffset;
              } else {
                  int fixOffset = fixLayoutStartGapExpose(startOffset, recycler, state, true);
                  startOffset += fixOffset;
                  endOffset += fixOffset;
                  fixOffset = fixLayoutEndGapExpose(endOffset, recycler, state, false);
                  startOffset += fixOffset;
                  endOffset += fixOffset;
              }
          }
          layoutForPredictiveAnimationsExpose(recycler, state, startOffset, endOffset);
          if (!state.isPreLayout()) {
              mCurrentPendingScrollPosition = RecyclerView.NO_POSITION;
              mPendingScrollPositionOffset = INVALID_OFFSET;
              mOrientationHelper.onLayoutComplete();
          }
          mLastStackFromEnd = getStackFromEnd();
          mCurrentPendingSavedState = null; // we don't need this anymore
          if (DEBUG) {
              validateChildOrderExpose();
          }
      }