LinearLayoutCompat源码浅析
1. LinearLayoutCompat是Google提供的Android.support.v7包中的布局容器,LinearLayoutCompat继承自ViewGroup,先来看源码中关于该类的注释:
* A Layout that arranges its children in a single column or a singlerow. The direction of
* the row can be set bycalling {@link #setOrientation(int) setOrientation()}.
* You can also specifygravity, which specifies the alignment of all the child elements by
* calling {@link#setGravity(int) setGravity()} or specify that specific children
* grow to fill up any remaining space in thelayout by setting the <em>weight</em> member of
* {@linkLinearLayoutCompat.LayoutParams LinearLayoutCompat.LayoutParams}.
* The default orientation ishorizontal.
这个Linearlayout布局可以单独作为子布局放在其他布局里,然后通过设置Orientation控制水平或者垂直,还可以设置对齐方式。
接下来看 LinearLayoutCompat 的几个重要的函数。2.LinearLayoutCompat的三个构造函数
// 创建视图的时候被调用,如果是从xml填充的视图,就不会调用这个
publicLinearLayoutCompat(Context context) {
this(context, null);
}
// 这个构造函数是在XML创建但是没有指定style的时候调用,
publicLinearLayoutCompat(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
// 这个构造函数系统不会自动调用,而是直接被第一个构造函数或者第二个构造函数调用。
public LinearLayoutCompat(Context context, AttributeSet attrs, intdefStyleAttr) {
super(context, attrs,defStyleAttr);
// 此处获取xml中的自定义布局属性
final TintTypedArray a= TintTypedArray.obtainStyledAttributes(context, attrs,
R.styleable.LinearLayoutCompat, defStyleAttr, 0);
int index =a.getInt(R.styleable.LinearLayoutCompat_android_orientation, -1);
if (index >= 0) {
setOrientation(index);
}
index = a.getInt(R.styleable.LinearLayoutCompat_android_gravity,-1);
if (index >= 0) {
setGravity(index);
}
booleanbaselineAligned =a.getBoolean(R.styleable.LinearLayoutCompat_android_baselineAligned, true);
if (!baselineAligned){
setBaselineAligned(baselineAligned);
}
mWeightSum =a.getFloat(R.styleable.LinearLayoutCompat_android_weightSum, -1.0f);
mBaselineAlignedChildIndex =
a.getInt(R.styleable.LinearLayoutCompat_android_baselineAlignedChildIndex,-1);
mUseLargestChild =a.getBoolean(R.styleable.LinearLayoutCompat_measureWithLargestChild, false);
setDividerDrawable(a.getDrawable(R.styleable.LinearLayoutCompat_divider));
mShowDividers =a.getInt(R.styleable.LinearLayoutCompat_showDividers, SHOW_DIVIDER_NONE);
mDividerPadding =a.getDimensionPixelSize(R.styleable.LinearLayoutCompat_dividerPadding, 0);
a.recycle();
}
3. LinearLayoutCompat的onDraw函数,这里主要分析垂直状态下的drawDividersVertical函数
void drawDividersVertical(Canvas canvas) {
final int count = getVirtualChildCount();
// 循环遍历布局容器中的所有子控件
for (int i = 0; i < count; i ){
final View child = getVirtualChildAt(i);
if (child != null && child.getVisibility() != GONE) {
// 此处检测是否需要在子控件之前画线,并根据布局参数画线。
if(hasDividerBeforeChildAt(i)) {
final LayoutParams lp =(LayoutParams) child.getLayoutParams();
final int top =child.getTop() - lp.topMargin - mDividerHeight;
drawHorizontalDivider(canvas, top);
}
}
}
//此处检测是否需要在子控件之前画线,并根据布局参数画线。
if (hasDividerBeforeChildAt(count)) {
final View child = getVirtualChildAt(count - 1);
int bottom = 0;
if (child == null) {
bottom = getHeight() -getPaddingBottom() - mDividerHeight;
} else {
final LayoutParams lp =(LayoutParams) child.getLayoutParams();
bottom =child.getBottom() lp.bottomMargin;
}
drawHorizontalDivider(canvas, bottom);
}
}
4.LinearLayoutCompat的onLayout函数,此处也以垂直方向的layout函数为例进行分析:
void layoutVertical(int left, int top, intright, int bottom) {
// 此处定义一些布局变量
final int paddingLeft = getPaddingLeft();
int childTop;
int childLeft;
// Where right end of child should go
final int width = right - left;
int childRight = width - getPaddingRight();
// Space available for child
int childSpace = width - paddingLeft - getPaddingRight();
final int count = getVirtualChildCount();
final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
final int minorGravity = mGravity &GravityCompat.RELATIVE_HORIZONTAL_GRAVITY_MASK;
// 设置对其方式
switch (majorGravity) {
case Gravity.BOTTOM:
// mTotalLength contains thepadding already
childTop = getPaddingTop() +bottom - top - mTotalLength;
break;
// mTotalLength contains the padding already
case Gravity.CENTER_VERTICAL:
childTop = getPaddingTop() +(bottom - top - mTotalLength) / 2;
break;
case Gravity.TOP:
default:
childTop = getPaddingTop();
break;
}
// 循环遍历布局中所有的子控件
for (int i = 0; i < count; i++) {
final View child = getVirtualChildAt(i);
if (child == null) {
childTop +=measureNullChild(i);
} else if (child.getVisibility() != GONE) {
final int childWidth =child.getMeasuredWidth();
final int childHeight =child.getMeasuredHeight();
finalLinearLayoutCompat.LayoutParams lp =
(LinearLayoutCompat.LayoutParams)child.getLayoutParams();
int gravity = lp.gravity;
if (gravity < 0) {
gravity = minorGravity;
}
final int layoutDirection =ViewCompat.getLayoutDirection(this);
final int absoluteGravity =GravityCompat.getAbsoluteGravity(gravity,
layoutDirection);
switch (absoluteGravity &Gravity.HORIZONTAL_GRAVITY_MASK) {
caseGravity.CENTER_HORIZONTAL:
childLeft =paddingLeft + ((childSpace - childWidth) / 2)
+lp.leftMargin - lp.rightMargin;
break;
case Gravity.RIGHT:
childLeft = childRight- childWidth - lp.rightMargin;
break;
case Gravity.LEFT:
default:
childLeft =paddingLeft + lp.leftMargin;
break;
}
// 先判断自布局是否画线
if(hasDividerBeforeChildAt(i)) {
childTop +=mDividerHeight;
}
childTop += lp.topMargin;
setChildFrame(child,childLeft, childTop + getLocationOffset(child),
childWidth,childHeight);
childTop += childHeight +lp.bottomMargin + getNextLocationOffset(child);
i +=getChildrenSkipCount(child, i);
}
}
}
以上,谢谢!下次写个demo再贴上来。