Android RecyclerView源码学习

RecyclerView 的三驾马车

LayoutManager

掌管RecyclerView的布局,你可以通过它实现一个listview、gridview、瀑布流等效果。LayoutManager主要作用与RecyclerView的measure和layout过程中。LayoutManager是RecyclerView中的一个内部抽象类,具体实现类有GridLayoutManager,LinearLayoutManager,StaggerLayoutManager等。每一个LayoutManager只能和一个RecyclerView绑定,调用setLayoutManager后,当一个LayoutManager被绑定到RecyclerView的时候,会回调LayoutManager的onAttachedToWindow接口。

measure

视图测绘的过程中,ViewRootImpl会执行perforMeasure方法,然后View的measure方法会被调用,同时注意measure方法是final不可重写,同时在measure中调用了相应View的onMeasure,所以我们只要查看onMeasure即可。我们可以实现LayoutManager中的onMeasure方法完成整个recyclerView的测量,来标定其大小,否则RecyclerView会直接调用其默认measure方法,也就是我们通常设置在LayoutParams中的大小,完成对RececylerView整个大小的measure。当通过adapter向RecyclerView中添加child view后,在进行addView的时候又会根据子View的LayoutParams进行child view的布局。

layout

layout则由onLayout中实现,调用 dispatchLayout() ,其中调用 onLayoutChildren,即可以调用到LayoutManager具体实现的onLayoutChildren。

在RecyclerView 进行 onMeasure的时候,调用了如下代码:

        if (mLayout == null) {
            defaultOnMeasure(widthSpec, heightSpec);
        } else {
            mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec);
        }

如果我们设置了LayoutManager,那么则由LayoutManager的onMeasure来完成测绘。然后去看实现类,以LinearLayoutManager为例,我们会发现其中并没有onMeasure的实现,这是因为

Adapter

LayoutManager负责布局,而adapter就是负责数据,以及每一个child view的提供。

ViewHolder

adapter中getCount,getItem等方法有点类似ListView,ViewHolder有点类似ListView中我们自定义用来回收利用convertView 的holder。只不过这里进一步的封装,并有recyclerview去调度管理。

ViewHolder构造代码如下:

        public ViewHolder(View itemView) {
            if (itemView == null) {
                throw new IllegalArgumentException("itemView may not be null");
            }
            this.itemView = itemView;
        }

其中将我们定义的View绑定在了ViewHolder中。通过自定义adapter,主要重写的方法是onCreateViewHolder和onBindViewHolder。我们的onCreateViewHolder会在Adapter中的 createViewHolder调用,代码如下:

        public final VH createViewHolder(ViewGroup parent, int viewType) {
            TraceCompat.beginSection(TRACE_CREATE_VIEW_TAG);
            final VH holder = onCreateViewHolder(parent, viewType);
            holder.mItemViewType = viewType;
            TraceCompat.endSection();
            return holder;
    }

而createViewHolder又会在getViewForPosition方法中被调用,其中会经历检查无用的ViewHolder,可以回收的ViewHolder一系列过程,最后如果没有会调用adapter的createViewHolder,在其中还会调用bindViewHolder,也就是我们实现的方法完成视图和数组的绑定。

ViewHolder中的ItemView

ItemDecoration

ItemDecoration负责每一个ItemView的padding修整,背景以及蒙层绘制。

在说明ItemDecoration之前首先要看一下view中draw事件的传递:

View的绘制过程通过dispatchView实现,会调用所有子view的draw方法,draw事件被一层一层传递下去。在View的默认实现draw中,遵循以下流程:
1. 绘制背景 drawBackground
2. 绘制视图内容,即调用自身的 onDraw
3. 绘制child view

使用ItemDecoration,主要通过覆写以下方法:

getItemOffsets

可以通过对outRect.set的设置,设置list中每个item的padding值。在RecyclerView 对子view,也就是每个item进行测绘的时候,measureChild中有以下代码:

onDraw

RecyclerView 被父布局调用draw方法,draw方法中关键代码:

    public void draw(Canvas c) {
        super.draw(c);
        final int count = mItemDecorations.size();
        for (int i = 0; i < count; i++) {
            mItemDecorations.get(i).onDrawOver(c, this, mState);
        }
        ...
    }

其中super.draw 调用了view的默认实现,那么会调用自身的onDraw方法,Recyclerview的onDraw中有:

    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);
        }
    }

也就是说,recyclerview进行绘制的时候,首先绘制背景,然后调用了ItemDecoration 的onDraw方法,之后对child进行绘制,然后最后调用了onDrawOver方法。因为Canvas是每一层都绘制在原始的层面之上的,所以我们可以认为ItemDecoration中,onDraw是绘制每个item的背景,onDrawOver是最后再在最上面绘制一层。所以我们可以利用这两个方法绘制背景或者绘制蒙层。而getViewForPosition这个方法,则是由LayoutManager在onLayoutChildren布局的时候,最终调用到的方法:

        View next(RecyclerView.Recycler recycler) {
            if (mScrapList != null) {
                return nextViewFromScrapList();
            }
            final View view = recycler.getViewForPosition(mCurrentPosition);
            mCurrentPosition += mItemDirection;
            return view;
        }

measureChild 时候有 getItemDecorInsetsForChild,其中调用了getItemOffsets,然后依据此计算了 child 中外层layout的params,实现child的测绘,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值