LinearLayoutCompat源码浅析

LinearLayoutCompat源码浅析

1. LinearLayoutCompatGoogle提供的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. LinearLayoutCompatonDraw函数,这里主要分析垂直状态下的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.LinearLayoutCompatonLayout函数,此处也以垂直方向的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再贴上来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值