美文网首页
ListView绘制流程浅析

ListView绘制流程浅析

作者: magicyoung | 来源:发表于2018-01-20 18:38 被阅读0次
    AdapterView

    AdapterView是所有使用到Adapter的父类,AdapterView显示的列表项内容由Adapter提供

    AdapterView派生三个子类:

    AbsListView、AbsSpinner、AdapterViewAnimator

    (1)ListView:列表

    (2)Spinner:下拉选择列表,给用户提供选择

    (3)Gallery:画廊,水平滚动的列表

    (4)GridView:网格图

    Adapter

    作为View和数据之间的桥梁

    可以把AdapterView当做View层,Adapter为Control层,数据则是Model层。

    绘制流程

    作为ViewGroup的子类,AdapterView仅仅重写了onLayout方法,返回一个 mLayoutHeight,其余的交由子类实现。

    那么,看一下其中最常用的AbsListView的实现

    //子类不可重写该方法

    /** * Subclasses should NOT override this method but * {@link #layoutChildren()} instead. */

    @Override

    protected void onLayout(boolean changed, int l, int t, int r, int b) {

    super.onLayout(changed, l, t, r, b);

        mInLayout =true;

        final int childCount = getChildCount();

        if (changed) {

    //遍历所有子view,做 forceLayout()

    for (int i =0; i < childCount; i++) {

    getChildAt(i).forceLayout();   

            }

    mRecycler.markChildrenDirty();

        }

    //触发子类需要重写的方法,

    layoutChildren();

        mInLayout =false;

        mOverscrollMax = (b - t) /OVERSCROLL_LIMIT_DIVISOR;

        // TODO: Move somewhere sane. This doesn't belong in onLayout().

        if (mFastScroll !=null) {

    mFastScroll.onItemCountChanged(getChildCount(), mItemCount);

        }

    }

    AbsListView的 onMeasure 仅在 TRANSCRIPT_MODE_NORMAL 模式下做了一次mForceTranscriptScroll支持,真正的方法实现还是交于了实现类

    mRecycler是ABsList中的类RecycleBin,存储了View的两级缓存

    activeViews:是一个一维数组,包含当前屏幕展示的所有View

    scrapViews:二维数组,第二维长度对应ViewTypeCount的返回值,下标与Adapter.getItemViewType对应

    public void markChildrenDirty() {

    //只有一种ViewType时

    if (mViewTypeCount ==1) {

    final ArrayList scrap =mCurrentScrap;

            final int scrapCount = scrap.size();

            for (int i =0; i < scrapCount; i++) {

    scrap.get(i).forceLayout();

            }

    }else {

    //将二维 mScrapViews 所有的View刷新一遍

    final int typeCount =mViewTypeCount;

            for (int i =0; i < typeCount; i++) {

    final ArrayList scrap =mScrapViews[i];

                final int scrapCount = scrap.size();

                for (int j =0; j < scrapCount; j++) {

    scrap.get(j).forceLayout();

                }

    }

    }

    ***

    }

    }

    ListView 的layoutChildren方法流程较为复杂,这里介绍了与缓存的修改流程。

    1.如果dataChanged则执行2,否则执行3

    2.从mFirstPosition开始,依次将childCount个子View执行recycleBin.addScrapView(getChildAt(i), firstPosition+i);

    3.从mFirstPosition开始,将所有的childView(非HEADER_OR_FOOTER)添加入RecycleBin的activeViews中,同时修改其param.scrappedFromPosition为缓存时候的position

    4.执行detachAllViewsFromParent,将所有子View与其parent设置为null

    5.对RecycleBin的mSkippedScrap中所有View调用removeDetachedView

    6.根据传入的mLayoutMode,重新进行fill,同时触发scrapActiveViews

    7.更新HEADER和FOOTER


    在具体的fill过程中,触发makeAndAddView()

    1.如果dataChanged则执行2,否则执行4

    2.如果mAdapterHasStableIds,则去mTransientStateViewsById获取,否则从mTransientStateViews获取View

    3.如果步骤2获取为null,根据ViewTypeCount分别从mCurrentScrap,mScrapViews中获取scrapView,并且调用mAdapter.getView(position, scrapView, this)

    4.从recycleBin.activeViews中获取View

    5.重新对获取的Viewz做setupChild

    缓存未命中

    obtainView方法中,getScrapView会遍历每个Id或者position是否与之前设定的 相同(id == params.itemId 或者params.scrappedFromPosition ==position),否则将返回scrapViews的最后一个View

    相关文章

      网友评论

          本文标题:ListView绘制流程浅析

          本文链接:https://www.haomeiwen.com/subject/hkitaxtx.html