LinearLayoutCompat是个很神奇的类,在我们写布局的时候我们经常用用view这个空间来画一条线,导致布局中有很多这样的无用布局,但是不写又不符合界面设置规范,用listview来写,条目很少,没必要,各种纠结。让我们来认识下LinearLayoutCompat这个类吧,原生的,带你飞起来,你会有相见恨晚的感觉。
效果图:
** <android.support.v7.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:divider="@android:drawable/divider_horizontal_bright"
android:showDividers="middle"
android:orientation="vertical"
android:layout_height="match_parent">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="listPop"
android:text="listPop"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</android.support.v7.widget.LinearLayoutCompat>**
好想LinearLayout也可以在4.0以上,具体没尝试;大家可以试试;直接用LinearLayout;不用着个v7兼容包的类。
————————————————-正式进入源码分析————————————
第一步我们打开v7包在android.support.v7.widget.LinearLayoutCompat中的源码(源码在哪,你能来看就不要问我了,对吧!!)
然后,先看头部注释;这个很重用,一般这个注释都归纳了这个类的作用、用法等
A Layout that arranges its children in a single column or a single row. The direction of
the row can be set by calling {@link #setOrientation(int) setOrientation()}.
You can also specify gravity, 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 the layout by setting the weight member of
{@link LinearLayoutCompat.LayoutParams LinearLayoutCompat.LayoutParams}.
The default orientation is horizontal.
Also see {@link LinearLayoutCompat.LayoutParams} for layout attributes
这里主要讲的是这个类是一个布局,可以将其放置在一个单独列或一行中,可以设置方向,对齐方式等。。
我们在往下看:构造函数—实现3个函数,在最后一个构造函数中实现初始化;
在看看onDraw方法,这是这个类效果绘制的方法;
@Override
protected void onDraw(Canvas canvas) {
//这里要设置mDivider要注意,不设置是是不会画后面的线的
if (mDivider == null) {
return;
}
//根据方向画线
if (mOrientation == VERTICAL) {
drawDividersVertical(canvas);
} else {
drawDividersHorizontal(canvas);
}
}
//画垂直线
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 = getLastNonGoneChild();
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);
}
}
//调用Drawable这个工具类来画图
void drawHorizontalDivider(Canvas canvas, int top) {
//在看这个类的时候,我们要注意一些方法:Drawable类最前面的注释;基本上你就能大体掌握这个类,下次我专门搞个详解;
mDivider.setBounds(getPaddingLeft() + mDividerPadding, top,
getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight);
mDivider.draw(canvas);
}
//画横线
void drawDividersHorizontal(Canvas canvas) {
final int count = getVirtualChildCount();
final boolean isLayoutRtl = ViewUtils.isLayoutRtl(this);
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 position;
if (isLayoutRtl) {
position = child.getRight() + lp.rightMargin;
} else {
position = child.getLeft() - lp.leftMargin - mDividerWidth;
}
drawVerticalDivider(canvas, position);
}
}
}
if (hasDividerBeforeChildAt(count)) {
final View child = getVirtualChildAt(count - 1);
int position;
if (child == null) {
if (isLayoutRtl) {
position = getPaddingLeft();
} else {
position = getWidth() - getPaddingRight() - mDividerWidth;
}
} else {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (isLayoutRtl) {
position = child.getLeft() - lp.leftMargin - mDividerWidth;
} else {
position = child.getRight() + lp.rightMargin;
}
}
drawVerticalDivider(canvas, position);
}
}
//上面已经说了
void drawVerticalDivider(Canvas canvas, int left) {
mDivider.setBounds(left, getPaddingTop() + mDividerPadding,
left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding);
mDivider.draw(canvas);
}
/**
* Determines where to position dividers between children.
*(判断子控件位置;也就是我们在xml中(begin|end|middle|none}))
* @param childIndex Index of child to check for preceding divider
* @return true if there should be a divider before the child at childIndex
* @hide Pending API consideration. Currently only used internally by the system.
*/
protected boolean hasDividerBeforeChildAt(int childIndex) {
if (childIndex == 0) {
return (mShowDividers & SHOW_DIVIDER_BEGINNING) != 0;
} else if (childIndex == getChildCount()) {
return (mShowDividers & SHOW_DIVIDER_END) != 0;
} else if ((mShowDividers & SHOW_DIVIDER_MIDDLE) != 0) {
boolean hasVisibleViewBefore = false;
for (int i = childIndex - 1; i >= 0; i--) {
if (getChildAt(i).getVisibility() != GONE) {
hasVisibleViewBefore = true;
break;
}
}
return hasVisibleViewBefore;
}
return false;
}
好了,看了这么多的源码,你总改有所了解了吧