RecyclerView与ListView对比浅析(三):绘制

上一篇:RecyclerView与ListView对比浅析(二):View缓存篇


(三)绘制篇

1. AbsListView(源码版本 4.4)

绘制就分三步来分析Measure、Layout和Draw

  (1)onMeasure里未用到MeasureSpec的高宽,首先设Selector,然后根据SelectionPadding和mPadding算出ListPadding的上下左右。最后根据TranscriptMode,决定Scroll和Measure的先后顺序。

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mSelector == null) {
            useDefaultSelector();
        }
        final Rect listPadding = mListPadding;
        listPadding.left = mSelectionLeftPadding + mPaddingLeft;
        listPadding.top = mSelectionTopPadding + mPaddingTop;
        listPadding.right = mSelectionRightPadding + mPaddingRight;
        listPadding.bottom = mSelectionBottomPadding + mPaddingBottom;

        // Check if our previous measured size was at a point where we should scroll later.
        if (mTranscriptMode == TRANSCRIPT_MODE_NORMAL) {
            final int childCount = getChildCount();
            final int listBottom = getHeight() - getPaddingBottom();
            final View lastChild = getChildAt(childCount - 1);
            final int lastBottom = lastChild != null ? lastChild.getBottom() : listBottom;
            mForceTranscriptScroll = mFirstPosition + childCount >= mLastHandledItemCount &&
                    lastBottom <= listBottom;
        }
   }

  (2)onLayout中,首先调super.onLayout,然后:

   a. 如果changed为true,遍历拿到所有Child执行forceLayout():清空MeasureCache,设mPrivateFlags为FORCE_LAYOUT,然后调mRecycler的markChildrenDirty():对所有缓存的View执行forceLayout()

   b. 如果mFastScroller不为空且ItemCount变了,调mFastScroller的onItemCountChanged。

   c. 调layoutChildren(),需由子类实现

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        mInLayout = true;
        if (changed) {
            int childCount = getChildCount();
            for (int i = 0; i < childCount; i++) {
                getChildAt(i).forceLayout();
            }
            mRecycler.markChildrenDirty();
        }

        if (mFastScroller != null && (mItemCount != mOldItemCount || mDataChanged)) {
            mFastScroller.onItemCountChanged(mItemCount);
        }

        layoutChildren();
        mInLayout = false;

        mOverscrollMax = (b - t) / OVERSCROLL_LIMIT_DIVISOR;
    }

  (3)draw调完super.draw后,处理了mEdgeGlowTop和mEdgeGlowBottom


2. ListView(源码版本 4.4)

同样分三步Measure、Layout和Draw继续分析:

   (1)onMeasure中,先调父类的onMeasure,然后调父类的obtainView拿到 位置为0的View(mIsScrap作为入参记录是否为ScrapView),调measureScrapChild对它Measure,拿到childWidth、childHeight和childState,然后判断这个Type的View是否需要回收,需要就调addScrapView(child, -1)。最后根据childWidth和childHeight算出widthSize和heightSize(不同Mode用不同的计算方法),调setMeasuredDivision。

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 设置mListPadding
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int childWidth = 0;
        int childHeight = 0;
        int childState = 0;

        mItemCount = mAdapter == null ? 0 : mAdapter.getCount();
        if (mItemCount > 0 && (widthMode == MeasureSpec.UNSPECIFIED ||
                heightMode == MeasureSpec.UNSPECIFIED)) {
            final View child = obtainView(0, mIsScrap);

            measureScrapChild(child, 0, widthMeasureSpec);

            childWidth = child.getMeasuredWidth();
            childHeight = child.getMeasuredHeight();
            childState = combineMeasuredStates(childState, child.getMeasuredState());

            if (recycleOnMeasure() && mRecycler.shouldRecycleViewType(
                    ((LayoutParams) child.getLayoutParams()).viewType)) {
                mRecycler.addScrapView(child, -1);
            }
        }

        if (widthMode == MeasureSpec.UNSPECIFIED) {
            widthSize = mListPadding.left + mListPadding.right + childWidth +
                    getVerticalScrollbarWidth();
        } else {
            widthSize |= (childState&MEASURED_STATE_MASK);
        }

        if (heightMode == MeasureSpec.UNSPECIFIED) {
            heightSize = mListPadding.top + mListPadding.bottom + childHeight +
                    getVerticalFadingEdgeLength() * 2;
        }

        if (heightMode == MeasureSpec.AT_MOST) {
            // TODO: 这里可以用首个可见View的位置,而不是0
            heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1);
        }

        setMeasuredDimension(widthSize , heightSize);
        mWidthMeasureSpec = widthMeasureSpec;        
    }

   (2)ListView没有重写onLayout,而是沿用父类的onLayout并实现了layoutChildren(),来看下layoutChildren的过程(源码见上一节);

a. 如果Adapter为空,则重置List,移除Layout中的所有View。

b. 根据LayoutMode选择不同Layout方式,这里只看default的方式:用getChildAt方法拿到几个View备用:原来选择的oldSel、原来在首位的oldFirst和新选择的newSel。

c. 如果dataChanged为true,调handleDataChanged()处理选择和同步的相应变化。

d. 所有ChildView放入RecycleBin,数据变了就放ScrapViews,没变就放ActiveViews,然后detach所有旧View。

e. 根据LayoutMode,进行View填充,这里也是只看default方法:如果childCount==0,就根据List是自顶向下还是自底向上选择fill方法,正常是选择fillFromTop(childrenTop)进行填充;如果不为0,则根据先前计算的SelectionPosition调fillSpecific填充特定的View。

f. fill完毕后,把所有ActiveViews存入ScrapView

在这里重点分析下fillFromTop的源码:

// 从上向下在ListView中填充Item View
private View fillFromTop(int nextTop) {
     mFirstPosition = Math.min(mFirstPosition, mSelectedPosition);
     mFirstPosition = Math.min(mFirstPosition, mItemCount - 1);
     if (mFirstPosition < 0) {
         mFirstPosition = 0;
     }
     // 具体操作在此
     return fillDown(mFirstPosition, nextTop);
}

// 在位置pos下面填充Item View
private View fillDown(int pos, int nextTop) {
    View selectedView = null;
    // ListView getHeight也是这样计算的
    int end = (mBottom - mTop);
    ……
    // 初始化时pos = 0,如果item总数少于一屏幕,执行mItemCount - pos次。如果item多于一屏幕,执行end - nextTop次。
    while (nextTop < end && pos < mItemCount) {
        // is this the selected item?
        boolean selected = pos == mSelectedPosition;
        // 获取Item View对象,在View缓存中已经介绍过了,如果数据没变,从ActiveViews里拿,如果变了,调obtainView查找缓存拿View
        View child = makeAndAddView(pos, nextTop, true, mListPadding.left, selected);
        nextTop = child.getBottom() + mDividerHeight;
        if (selected) {
            selectedView = child;
        }
            pos++;
    }
    setVisibleRangeHint(mFirstPosition, mFirstPosition + getChildCount() - 1);
    return selectedView;
}

在makeAndAddView中,拿到View后,还会调setupChild进行状态设置

    private void setupChild(View child, int position, int y, boolean flowDown, int childrenLeft,
            boolean selected, boolean recycled) {
        // 判断当前Item View是否选中状态
        final boolean isSelected = selected && shouldShowSelector();
        final boolean updateChildSelected = isSelected != child.isSelected();
        
        final int mode = mTouchMode;
        
        // 是否处于按下状态
        final boolean isPressed = mode > TOUCH_MODE_DOWN && mode < TOUCH_MODE_SCROLL &&
                mMotionPosition == position;
        final boolean updateChildPressed = isPressed != child.isPressed();
        
        // 是否需要重新measure与layout
        final boolean needToMeasure = !recycled || updateChildSelected || child.isLayoutRequested();

        // Respect layout params that are already in the view. Otherwise make some up...
        // noinspection unchecked
        AbsListView.LayoutParams p = (AbsListView.LayoutParams) child.getLayoutParams();
        if (p == null) {
            p = (AbsListView.LayoutParams) generateDefaultLayoutParams();
        }
        p.viewType = mAdapter.getItemViewType(position);

        if ((recycled && !p.forceAdd) || (p.recycledHeaderFooter &&
                p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER)) {
            attachViewToParent(child, flowDown ? -1 : 0, p);
        } else {
            p.forceAdd = false;
            if (p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
                p.recycledHeaderFooter = true;
            }
            // 向ListView(ViewGroup子类)添加当前Item View
            addViewInLayout(child, flowDown ? -1 : 0, p, true);
        }

        // 更新选中状态
        if (updateChildSelected) {
            child.setSelected(isSelected);
        }

        // 更新按下状态
        if (updateChildPressed) {
            child.setPressed(isPressed);
        }

        if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) {
            if (child instanceof Checkable) {
                ((Checkable) child).setChecked(mCheckStates.get(position));
            } else if (getContext().getApplicationInfo().targetSdkVersion
                    >= android.os.Build.VERSION_CODES.HONEYCOMB) {
                child.setActivated(mCheckStates.get(position));
            }
        }

        if (needToMeasure) {
            int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec,
                    mListPadding.left + mListPadding.right, p.width);
            int lpHeight = p.height;
            int childHeightSpec;
            if (lpHeight > 0) {
                childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
            } else {
                childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
            }
           // 与普通视图的measure流程不同,ListView是在此处执行具体的当前Item View measure
            child.measure(childWidthSpec, childHeightSpec);
        } else {
            cleanupLayoutState(child);
        }

        final int w = child.getMeasuredWidth();
        final int h = child.getMeasuredHeight();
        final int childTop = flowDown ? y : y - h;

        if (needToMeasure) {
            final int childRight = childrenLeft + w;
            final int childBottom = childTop + h;
            // 大小改变肯定位置也会发生变化,当前Item View重新进行layout
            child.layout(childrenLeft, childTop, childRight, childBottom);
        } else {
            child.offsetLeftAndRight(childrenLeft - child.getLeft());
            child.offsetTopAndBottom(childTop - child.getTop());
        }

        if (mCachingStarted && !child.isDrawingCacheEnabled()) {
            child.setDrawingCacheEnabled(true);
        }

        if (recycled && (((AbsListView.LayoutParams)child.getLayoutParams()).scrappedFromPosition)
                != position) {
            child.jumpDrawablesToCurrentState();
        }
    }

(3)ListView沿用了父类的draw方法。


3. RecyclerView(源码版本 5.1.1)

同样分三步分析,Measure、Layout和Draw

 

(1)onMeasure

   @Override
protected void onMeasure(int widthSpec, int heightSpec) {
    //Adapter在Measure过程中执行了更新
        if (mAdapterUpdateDuringMeasure) {
            //中止Layout请求
eatRequestLayout();
//执行更新并且设置动画
            processAdapterUpdatesAndSetAnimationFlags();

if (mState.mRunPredictiveAnimations) {
    //处理Predictive动画的机制
                // TODO: try to provide a better approach.
                // When RV decides to run predictive animations, we need to measure in pre-layout
                // state so that pre-layout pass results in correct layout.
                // On the other hand, this will prevent the layout manager from resizing properly.
                mState.mInPreLayout = true;
            } else {
                // consume remaining updates to provide a consistent state with the layout pass.
                mAdapterHelper.consumeUpdatesInOnePass();
                mState.mInPreLayout = false;
            }
mAdapterUpdateDuringMeasure = false;
//恢复Layout请求
            resumeRequestLayout(false);
        }

        if (mAdapter != null) {
            mState.mItemCount = mAdapter.getItemCount();
        } else {
            mState.mItemCount = 0;
        }
        if (mLayout == null) {
            //默认Measure方法
            defaultOnMeasure(widthSpec, heightSpec);
        } else {
            //调LayoutManager的onMeasure
            mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);
        }

        mState.mInPreLayout = false; // clear
    }

    首先看defaultOnMeasure,与普通View的Measure基本相似,都是根据Mode得出对应的高宽,最后setMeasuredDimision。而LayoutManager的onMeasure就是调mRecyclerView.defaultOnMeasure,就不贴代码了。

    private void defaultOnMeasure(int widthSpec, int heightSpec) {
        final int widthMode = MeasureSpec.getMode(widthSpec);
        final int heightMode = MeasureSpec.getMode(heightSpec);
        final int widthSize = MeasureSpec.getSize(widthSpec);
        final int heightSize = MeasureSpec.getSize(heightSpec);

        int width = 0;
        int height = 0;

        switch (widthMode) {
            case MeasureSpec.EXACTLY:
            case MeasureSpec.AT_MOST:
                width = widthSize;
                break;
            case MeasureSpec.UNSPECIFIED:
            default:
                width = ViewCompat.getMinimumWidth(this);
                break;
        }

        switch (heightMode) {
            case MeasureSpec.EXACTLY:
            case MeasureSpec.AT_MOST:
                height = heightSize;
                break;
            case MeasureSpec.UNSPECIFIED:
            default:
                height = ViewCompat.getMinimumHeight(this);
                break;
        }

        setMeasuredDimension(width, height);
    }

(2)onLayout

    @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    //中止Layout请求
        eatRequestLayout();
        //分发Layout任务
        dispatchLayout();
        //恢复Layout请求
        resumeRequestLayout(false);
        mFirstLayoutComplete = true;
    }

DispatchLayout()是其中的关键函数,首先看下函数描述:在layoutChildren()外面包一层,用于处理layout引发的动画变化。这里的layoutChildren()就是表示前面介绍的LayoutManager中的onLayoutChildren(),处理各个Child的Measure操作。源码很长,就分步看下吧:

    void dispatchLayout() {
        if (mAdapter == null) {
            Log.e(TAG, "No adapter attached; skipping layout");
            return;
        }
        if (mLayout == null) {
            Log.e(TAG, "No layout manager attached; skipping layout");
            return;
        }
        mDisappearingViewsInLayoutPass.clear();
        //这里再调一次中止Layout请求
        eatRequestLayout();
        mRunningLayoutOrScroll = true;
        //处理Adapter更新并设动画标志位
        processAdapterUpdatesAndSetAnimationFlags();
        //一些参数的初始化
        mState.mOldChangedHolders = mState.mRunSimpleAnimations && mItemsChanged
                && supportsChangeAnimations() ? new ArrayMap<Long, ViewHolder>() : null;
        mItemsAddedOrRemoved = mItemsChanged = false;
        ArrayMap<View, Rect> appearingViewInitialBounds = null;
        mState.mInPreLayout = mState.mRunPredictiveAnimations;
        mState.mItemCount = mAdapter.getItemCount();
        findMinMaxChildLayoutPositions(mMinMaxLayoutPositions);

        if (mState.mRunSimpleAnimations) {
            // 准备工作:找到所有免移除的item,执行预layout
            mState.mPreLayoutHolderMap.clear();
            mState.mPostLayoutHolderMap.clear();
            int count = mChildHelper.getChildCount();
            for (int i = 0; i < count; ++i) {
                final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
                //判断条件:是否忽视、是否合法、Adapter是否有StableId
                if (holder.shouldIgnore() || (holder.isInvalid() && !mAdapter.hasStableIds())) {
                    continue;
                }
                final View view = holder.itemView;
                mState.mPreLayoutHolderMap.put(holder, new ItemHolderInfo(holder,
                        view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
            }
        }
        if (mState.mRunPredictiveAnimations) {
        // 第一步:执行预Layout,需要用到item的原位置。LayoutManager会对所有元素进行layout,包括已移除item(但不会把已移除项再加回来)。这就能让pre-layout拿到用户可见View的position,真正执行layout时不会变。
            //存储原位置方便LayoutManager执行映射逻辑
            saveOldPositions();
//前面的processAdapterUpdatesAndSetAnimationFlags已经对动画执行了预Layiout
//遍历mChildHelper,将里面已改变、未移除且不该忽略的holder移出预Layout容器
            if (mState.mOldChangedHolders != null) {
                int count = mChildHelper.getChildCount();
                for (int i = 0; i < count; ++i) {
                    final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
                    if (holder.isChanged() && !holder.isRemoved() && !holder.shouldIgnore()) {
                        long key = getChangedHolderKey(holder);
                        mState.mOldChangedHolders.put(key, holder);
                        mState.mPreLayoutHolderMap.remove(holder);
                    }
                }
            }

final boolean didStructureChange = mState.mStructureChanged;
//因为是预Layout,暂时把此标志位置false
            mState.mStructureChanged = false;
            //执行onLayoutChildren,不同的LayoutManager子类有不同的实现
            mLayout.onLayoutChildren(mRecycler, mState);
            mState.mStructureChanged = didStructureChange;

            //设置即将显示View的对应Bounds
            appearingViewInitialBounds = new ArrayMap<View, Rect>();
            for (int i = 0; i < mChildHelper.getChildCount(); ++i) {
                boolean found = false;
                View child = mChildHelper.getChildAt(i);
                if (getChildViewHolderInt(child).shouldIgnore()) {
                    continue;
                }
                for (int j = 0; j < mState.mPreLayoutHolderMap.size(); ++j) {
                    ViewHolder holder = mState.mPreLayoutHolderMap.keyAt(j);
                    if (holder.itemView == child) {
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    appearingViewInitialBounds.put(child, new Rect(child.getLeft(), child.getTop(),
                            child.getRight(), child.getBottom()));
                }
            }
// 不处理disappearingList是因为它会在Post Layout的时候处理
clearOldPositions();
            mAdapterHelper.consumePostponedUpdates();
        } else {
        //执行完预Layout但决定不执行Predictive动画的情况
            clearOldPositions();
mAdapterHelper.consumeUpdatesInOnePass();
//遍历mChildHelper,对mState里的两容器的元素进行更新
            if (mState.mOldChangedHolders != null) {
                int count = mChildHelper.getChildCount();
                for (int i = 0; i < count; ++i) {
                    final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
                    if (holder.isChanged() && !holder.isRemoved() && !holder.shouldIgnore()) {
                        long key = getChangedHolderKey(holder);
                        mState.mOldChangedHolders.put(key, holder);
                        mState.mPreLayoutHolderMap.remove(holder);
                    }
                }
            }
        }
        mState.mItemCount = mAdapter.getItemCount();
        mState.mDeletedInvisibleItemCountSincePreviousLayout = 0;

        //第二步:执行Layout
        mState.mInPreLayout = false;
        mLayout.onLayoutChildren(mRecycler, mState);

        mState.mStructureChanged = false;
        mPendingSavedState = null;

        // onLayoutChildren有可能导致禁用item动画,这里重新检查一下
        mState.mRunSimpleAnimations = mState.mRunSimpleAnimations && mItemAnimator != null;

        if (mState.mRunSimpleAnimations) {
            // 第三步:执行后Layout
            ArrayMap<Long, ViewHolder> newChangedHolders = mState.mOldChangedHolders != null ?
                    new ArrayMap<Long, ViewHolder>() : null;
            int count = mChildHelper.getChildCount();
            for (int i = 0; i < count; ++i) {
                ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i));
                if (holder.shouldIgnore()) {
                    continue;
                }
                final View view = holder.itemView;
                long key = getChangedHolderKey(holder);
                if (newChangedHolders != null && mState.mOldChangedHolders.get(key) != null) {
                    newChangedHolders.put(key, holder);
                } else {
                    //需要后layout处理的Holder存入这个容器
                    mState.mPostLayoutHolderMap.put(holder, new ItemHolderInfo(holder,
                            view.getLeft(), view.getTop(), view.getRight(), view.getBottom()));
                }
            }
            processDisappearingList(appearingViewInitialBounds);
            //第四步:执行移除和消失动画
            int preLayoutCount = mState.mPreLayoutHolderMap.size();
            for (int i = preLayoutCount - 1; i >= 0; i--) {
                ViewHolder itemHolder = mState.mPreLayoutHolderMap.keyAt(i);
                if (!mState.mPostLayoutHolderMap.containsKey(itemHolder)) {
                    ItemHolderInfo disappearingItem = mState.mPreLayoutHolderMap.valueAt(i);
                    mState.mPreLayoutHolderMap.removeAt(i);

                    View disappearingItemView = disappearingItem.holder.itemView;
                    mRecycler.unscrapView(disappearingItem.holder);
                    animateDisappearance(disappearingItem);
                }
            }
            // 第五步:执行新增动画
            int postLayoutCount = mState.mPostLayoutHolderMap.size();
            if (postLayoutCount > 0) {
                for (int i = postLayoutCount - 1; i >= 0; i--) {
                    ViewHolder itemHolder = mState.mPostLayoutHolderMap.keyAt(i);
                    ItemHolderInfo info = mState.mPostLayoutHolderMap.valueAt(i);
                    if ((mState.mPreLayoutHolderMap.isEmpty() ||
                            !mState.mPreLayoutHolderMap.containsKey(itemHolder))) {
                        mState.mPostLayoutHolderMap.removeAt(i);
                        Rect initialBounds = (appearingViewInitialBounds != null) ?
                                appearingViewInitialBounds.get(itemHolder.itemView) : null;
                        animateAppearance(itemHolder, initialBounds,
                                info.left, info.top);
                    }
                }
            }
            //第6步,执行永久项的动画
            count = mState.mPostLayoutHolderMap.size();
            for (int i = 0; i < count; ++i) {
                ViewHolder postHolder = mState.mPostLayoutHolderMap.keyAt(i);
                ItemHolderInfo postInfo = mState.mPostLayoutHolderMap.valueAt(i);
                ItemHolderInfo preInfo = mState.mPreLayoutHolderMap.get(postHolder);
                if (preInfo != null && postInfo != null) {
                    if (preInfo.left != postInfo.left || preInfo.top != postInfo.top) {
                        postHolder.setIsRecyclable(false);
                        if (DEBUG) {
                            Log.d(TAG, "PERSISTENT: " + postHolder +
                                    " with view " + postHolder.itemView);
                        }
                        if (mItemAnimator.animateMove(postHolder,
                                preInfo.left, preInfo.top, postInfo.left, postInfo.top)) {
                            postAnimationRunner();
                        }
                    }
                }
            }
            // 第7步:执行改变项的动画
            count = mState.mOldChangedHolders != null ? mState.mOldChangedHolders.size() : 0;
            // 逆向遍历以免View在遍历过程被回收
            for (int i = count - 1; i >= 0; i--) {
                long key = mState.mOldChangedHolders.keyAt(i);
                ViewHolder oldHolder = mState.mOldChangedHolders.get(key);
                View oldView = oldHolder.itemView;
                if (oldHolder.shouldIgnore()) {
                    continue;
                }
                if (mRecycler.mChangedScrap != null &&
                        mRecycler.mChangedScrap.contains(oldHolder)) {
                    animateChange(oldHolder, newChangedHolders.get(key));
                } else if (DEBUG) {
                    Log.e(TAG, "cannot find old changed holder in changed scrap :/" + oldHolder);
                }
            }
        }
        resumeRequestLayout(false);
        mLayout.removeAndRecycleScrapInt(mRecycler);
        mState.mPreviousLayoutItemCount = mState.mItemCount;
        mDataSetHasChangedAfterLayout = false;
        mState.mRunSimpleAnimations = false;
        mState.mRunPredictiveAnimations = false;
        mRunningLayoutOrScroll = false;
        mLayout.mRequestedSimpleAnimations = false;
        if (mRecycler.mChangedScrap != null) {
            mRecycler.mChangedScrap.clear();
        }
        mState.mOldChangedHolders = null;

        if (didChildRangeChange(mMinMaxLayoutPositions[0], mMinMaxLayoutPositions[1])) {
            notifyOnScrolled(0, 0);
        }
    }

由以上代码可知,onLayout分为预Layout、正式Layout和后Layout三步,这一操作主要是为了实现item的出现、消失等效果。


(3)onDraw()

   onDraw主要是调用的父类的onDraw,后面加入了itemDecorations的draw操作,它常用来画分隔线Divider。

    @Override
    public void onDraw(Canvas c) {
        super.onDraw(c);

        final int count = mItemDecorations.size();
        for (int i = 0; i < count; i++) {
            mItemDecorations.get(i).onDraw(c, this, mState);
        }
    }




你可能感兴趣的:(android)