实现功能
官方定义:A flexible view for providing a limited window into a large data set。简单来说就是一种可以通过灵活的视图形式展示大量数据的列表组件
设计哲学
我其实也并不知道该组件的设计思路是什么,所以是比较主观的
适配器
该组件需要用户提供相对规整的数据,以及数据对应的自定义的视图,用一个map去存储?不行的,有一个原因是自定义视图中的子view对应的数据也需要用户去决定,所以需要设计一个适配器来处理这样杂乱无章的数据与视图(整流),将通过适配器处理后的数据对象交给组件。
布局管理器
这么多视图,哪个视图放到哪也是一个问题?这就需要布局管理器,其需要整合目前市面是流行的布局且具有可扩展性,所以会设计出一个布局管理器
简单使用
List<String> mDatas = getDatas()
mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
//设置布局管理器
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
// 设置适配器
mRecyclerView.setAdapter(new HomeAdapter(mDatas))
// adapter
class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder>
{
private List<String> mDatas;
HomeAdpater(List<String> datas) {
this.mDatas = datas;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
MyViewHolder holder = new MyViewHolder(LayoutInflater.from(
HomeActivity.this).inflate(R.layout.item_home, parent,
false));
return holder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position)
{
holder.tv.setText(mDatas.get(position));
}
@Override
public int getItemCount()
{
return mDatas.size();
}
// Viewhodler类
class MyViewHolder extends ViewHolder
{
TextView tv;
public MyViewHolder(View view)
{
super(view);
tv = (TextView) view.findViewById(R.id.id_num);
}
}
}
源码分析
主体初始化
构造器
构造器的代码是在findViewById触发,其主要是初始化了三个类分别是
ChildHelper
,AdapterHelper
,LayoutManager
。ChildHelper
是管理recylerview的孩子节点的。AdapterHelper
官方解释是管理adapter的更新的类。最后一个前面提到了是管理布局形式的类
测量(onMeasure)
// 关键源码
protected void onMeasure(int widthSpec, int heightSpec) {
if (mLayout.isAutoMeasureEnabled()) {
...
if (mState.mLayoutStep == State.STEP_START) {
dispatchLayoutStep1();
}
mLayout.setMeasureSpecs(widthSpec, heightSpec);
mState.mIsMeasuring = true;
dispatchLayoutStep2();
// now we can get the width and height from the children.
mLayout.setMeasuredDimensionFromChildren(widthSpec, heightSpec);
...
}
}
由于系统自带的几个布局管理器默认设置了自动测量参数mAutoMeasure=ture,所以测量主要分两步,其中dispatchLayoutStep1,dispatchLayoutStep2。
- dispatchLayoutStep1
主要工作就是记录一些view的状态和初始化动画相关的类其中调用了addToPreLayout去存储当前view的状态
- dispatchLayoutStep2
这一步工作比较关键,用于测量+布局,全权交由布局管理器处理,这里我们以线性布局管理器举例,入口函数为onLayoutChinlder
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
...
// 寻找锚点,即确定布局的起始点
if (!mAnchorInfo.mValid || mPendingScrollPosition != NO_POSITION