太久没有好好学习Android的基础知识了,趁机好好静下心来学习、输出。
RelativeLayout绘制流程解析
RecyclerView绘制流程解析
前言
之前《View/ViewGroup 绘制流程和疑惑》写了关于ViewGroup的绘制流程,在此基础上,继续分析LinearLayout的绘制流程,其实无论时LinearLayout还是RelativeLayout,都是继承自ViewGroup,除了Measure流程重写之外,layout和draw基本延续了VIewGroup的一套。
从LinearLayout的绘制,也就是测量开始:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mOrientation == VERTICAL) {
// 垂直方向
measureVertical(widthMeasureSpec, heightMeasureSpec);
} else {
// 水平方向
measureHorizontal(widthMeasureSpec, heightMeasureSpec);
}
}
根据方向分成垂直和水平测量流程,这里仅讨论垂直方向
测量流程
这才正式开始了真正的垂直方向的测量流程:
- 首次测量,遍历测量子View,除了设置weight无法测量的子View;
- 计算更新最大的总高度;
- 若子View需要重新分配,则重新测量
- 计算测量更新最大的宽度
- 设置布局宽高
垂直测量
// 垂直测量
void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
mTotalLength = 0; // 总高度,子控件累加总高度
int maxWidth = 0; // 最大子控件的宽度
int childState = 0; // 子view测量状态
int alternativeMaxWidth = 0; // 没有设置weight的子view的最大宽度
int weightedMaxWidth = 0; // 设置weight的子view的最大宽度
boolean allFillParent = true; // 子控件全设置match_parent
float totalWeight = 0; // 子控件累加总权重(子控件设置了layout_weight)
final int count = getVirtualChildCount(); // 子控件总数量
// 测量模式
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
boolean matchWidth = false; // 有子View宽度设置为match_parent
// 是否跳过重新测量
boolean skippedMeasure = false;
// 基线子view
final int baselineChildIndex = mBaselineAlignedChildIndex;
// 跟setMeasureWithLargestChildEnabled()有关
// 当设定为true,所有有设定了weight的子View的最小高度是:最大的View的高度
final boolean useLargestChild = mUseLargestChild;
// 最大子控件的高度
int largestChildHeight = Integer.MIN_VALUE;
int consumedExcessSpace = 0;
// 需要测量的子View总数,不需要测量指的是设定了weight
int nonSkippedChildCount = 0;
// 首次测量,测量能测量到的子View的高度和最大宽度,不包括weight的子View
for (int i = 0; i < count; ++i) {
/**** 备注:第一次测量,见分析一 ****/
}
// 底部是否有分割线,计算最高高度
if (nonSkippedChildCount > 0 && hasDividerBeforeChildAt(count)) {
mTotalLength += mDividerHeight;
}
if (useLargestChild && (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED)) {
mTotalLength = 0;
//设置了 measureWithLargestChild 且 总高度无法确定,需要重新计算 mToatalLength
for (int i = 0; i < count; ++i) {
/**** 备注:见分析二 ****/
}
}
// 添加padding
mTotalLength += mPaddingTop + mPaddin