title: Android View系列(三)——LinearLayout源码分析
tag: Android源码
category: Android
date: 2019-04-29
文章目录
LinearLayout 源码分析
简介
LinearLayout是我们开发中最常用的布局之一了,就是我们所说的线程布局,其分水平(HORIZONTAL)和垂直(VERTICAL)两个方向进行布局,接下来我们就慢慢看看这个LinearLayout
首先看看类的继承关系
public class LinearLayout extends ViewGroup {
...
}
很明显,直接继承自ViewGroup,当然,其他常用的布局RealativeLayout、FrameLayout等都是直接继承ViewGroup的
接着简单看看LinearLayout中的一些属性吧
//水平方向和垂直方向
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
//几种分割线的状态
//不展示dividers
public static final int SHOW_DIVIDER_NONE = 0;
//展示dividers在group的前面
public static final int SHOW_DIVIDER_BEGINNING = 1;
//给viewgroup的每一个item之间都展示divider
public static final int SHOW_DIVIDER_MIDDLE = 2;
//展示在ViewGroup的后面
public static final int SHOW_DIVIDER_END = 4;
...
//基线对齐变量
@ViewDebug.ExportedProperty(category = "layout")
private boolean mBaselineAligned = true;
//基线对齐对象index
@ViewDebug.ExportedProperty(category = "layout")
private int mBaselineAlignedChildIndex = -1;
//基线的额外偏移量
@ViewDebug.ExportedProperty(category = "measurement")
private int mBaselineChildTop = 0;
//方向
@ViewDebug.ExportedProperty(category = "measurement")
private int mOrientation;
...
//对齐方式
private int mGravity = Gravity.START | Gravity.TOP;
//整个LinearLayout子View的高度和(Vertical)或者宽度和(Historical)
@ViewDebug.ExportedProperty(category = "measurement")
private int mTotalLength;
//权重和
@ViewDebug.ExportedProperty(category = "layout")
private float mWeightSum;
//权重最小尺寸对象
@ViewDebug.ExportedProperty(category = "layout")
private boolean mUseLargestChild;
//基线对齐相关
private int[] mMaxAscent;
private int[] mMaxDescent;
private static final int VERTICAL_GRAVITY_COUNT = 4;
//几种index
private static final int INDEX_CENTER_VERTICAL = 0;
private static final int INDEX_TOP = 1;
private static final int INDEX_BOTTOM = 2;
private static final int INDEX_FILL = 3;
//分割线相关
private Drawable mDivider;
private int mDividerWidth;
private int mDividerHeight;
private int mShowDividers;
private int mDividerPadding;
private int mLayoutDirection = View.LAYOUT_DIRECTION_UNDEFINED;
属性简单就看这么多吧,接着进入重点吧,看看LinearLayout是怎么测量、布局、绘制的
onMeasure
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mOrientation == VERTICAL) {
measureVertical(widthMeasureSpec, heightMeasureSpec);
} else {
measureHorizontal(widthMeasureSpec, heightMeasureSpec);
}
}
在onMeasure方法中,对方向进行了判断,来决定是垂直测量还是横向测量,我们就看垂直方向的吧
由于方法有点长,分几个部分一点一点看吧,先看这个函数内的一些变量吧
void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
//每次测量都会将ziView的高度和进行初始化
mTotalLength = 0;
//子View最大宽度,不包括含有layout_weight权重的子View
int maxWidth = 0;
//测量状态
int childState = 0;
//子View中layout_weight <= 0的最大高度
int alternativeMaxWidth = 0;
//子View中layout_weight > 0的最大高度
int weightedMaxWidth = 0;
//是否全是match_parent
boolean allFillParent = true;
//子View权重和
float totalWeight = 0;
//子View个数
final int count = getVirtualChildCount();
//测量模式
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
//为match_parent时未true
boolean matchWidth = false;
boolean skippedMeasure = false;
//基线对齐的对象index
final int baselineChildIndex = mBaselineAlignedChildIndex;
//权重最小尺寸对象
final boolean useLargestChild = mUseLargestChild;
//子View中最高高度
int largestChildHeight = Integer.MIN_VALUE;
int consumedExcessSpace = 0;
//能够显示的View个数
int nonSkippedChildCount = 0;
...
}
这些变量大致的意思都写在代码注释里了,简单过一下就ok了
接着看看方法内的后面一部分,测量所有的子View
void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
...