vlayout是阿里的一个开源ui框架,是一个实现多样的item的列表的神器,相信大多数开发者对于vlayout内部的实现原理不太了解。本篇文章就和大家一起探讨下valyout的内部原理:
用过vlayout的同学都知道他的主要几个关键类,首先是各种layoutHelper的实现类,VirtualLayoutManager,DelegateAdapter
阅读过RecycleView源码的同学都知道,layoutManager是一个核心的内部类,recycleView把添加到其中的view都是通过 layoutManager进行布局,当用户调用setLayoutmanager方法之后,就会触发requestLayout方法
/**
* Set the {@link LayoutManager} that this RecyclerView will use.
*
* <p>In contrast to other adapter-backed views such as {@link android.widget.ListView}
* or {@link android.widget.GridView}, RecyclerView allows client code to provide custom
* layout arrangements for child views. These arrangements are controlled by the
* {@link LayoutManager}. A LayoutManager must be provided for RecyclerView to function.</p>
*
* <p>Several default strategies are provided for common uses such as lists and grids.</p>
*
* @param layout LayoutManager to use
*/
public void setLayoutManager(LayoutManager layout) {
if (layout == mLayout) {
return;
}
stopScroll();
// TODO We should do this switch a dispatchLayout pass and animate children. There is a good
// chance that LayoutManagers will re-use views.
if (mLayout != null) {
// end all running animations
if (mItemAnimator != null) {
mItemAnimator.endAnimations();
}
mLayout.removeAndRecycleAllViews(mRecycler);
mLayout.removeAndRecycleScrapInt(mRecycler);
mRecycler.clear();
if (mIsAttached) {
mLayout.dispatchDetachedFromWindow(this, mRecycler);
}
mLayout.setRecyclerView(null);
mLayout = null;
} else {
mRecycler.clear();
}
// this is just a defensive measure for faulty item animators.
mChildHelper.removeAllViewsUnfiltered();
mLayout = layout;
if (layout != null) {
if (layout.mRecyclerView != null) {
throw new IllegalArgumentException("LayoutManager " + layout
+ " is already attached to a RecyclerView: " + layout.mRecyclerView);
}
mLayout.setRecyclerView(this);
if (mIsAttached) {
mLayout.dispatchAttachedToWindow(this);
}
}
mRecycler.updateViewCacheSize();
requestLayout();
}
requestLayout的调用势必就会触发recycle的onlayout方法,我们看下onLayout的源码
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
Trace.beginSection(TRACE_ON_LAYOUT_TAG);
dispatchLayout();
Trace.endSection();
mFirstLayoutComplete = true;
}
我们可以看到在onlayout方法中又调用了dispatchLaout方法,我们接着往下看
void dispatchLayout() {
if (mAdapter == null) {
Log.e(TAG, "No adapter attached; skipping layout");
// leave the state in START
return;
}
if (mLayout == null) {
Log.e(TAG, "No layout manager attached; skipping layout");
// leave the state in START
return;
}
mState.mIsMeasuring = false;
if (mState.mLayoutStep == State.STEP_START) {
dispatchLayoutStep1();
mLayout.setExactMeasureSpecsFrom(this);
dispatchLayoutStep2();
} else if (mAdapterHelper.hasUpdates() || mLayout.getWidth() != getWidth()
|| mLayout.getHeight() != getHeight()) {
// First 2 steps are done in onMeasure but looks like we have to run again due to
// changed size.
mLayout.setExactMeasureSpecsFrom(this);
dispatchLayoutStep2();
} else {
// always make sure we sync them (to ensure mode is exact)
mLayout.setExactMeasureSpecsFrom(this);
}
dispatchLayoutStep3();
}
在dispatchLaout方法,我们只关注一个比较重要的方法,dispatchLayoutStep2,我们看下这