View测量,布局,绘制三大流程

本文详细介绍了Android中View的测量(Measure)、布局(Layout)和绘制(Draw)过程。 Measure阶段,View的测量由`measure()`方法完成,它调用`onMeasure()`进行自定义测量,`measureChildren()`遍历并测量所有子View。Layout阶段,View的位置确定由`layout()`方法处理,通过`onLayout()`放置子View。Draw阶段,View及其内容的绘制涉及`onDraw()`、`dispatchDraw()`和`drawChild()`,绘制背景、内容、子元素及装饰等。
摘要由CSDN通过智能技术生成

Measure过程:

View方法:

1.public final void measure(int widthMeasureSpec, int heightMeasureSpec) {

………..

int cacheIndex = forceLayout ? -1 :mMeasureCache.indexOfKey(key);
if (cacheIndex < 0 || sIgnoreMeasureCache) {
    // measure ourselves, this should setthe measured dimension flag back
    onMeasure(widthMeasureSpec,heightMeasureSpec);
    mPrivateFlags3 &=~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
} else {
    long value =mMeasureCache.valueAt(cacheIndex);
    // Casting a long to int drops thehigh 32 bits, no mask needed
    setMeasuredDimensionRaw((int) (value>> 32), (int) value);
    mPrivateFlags3 |=PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
}

………….

Measure方法时final,View的子类不允许重写该方法,在这个方法中去调用onMeasure方法

2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
   setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(),widthMeasureSpec),
           getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}

Measure方法中调用setMeasuredDimension设置测量值

上述两个方法中的参数(int widthMeasureSpec, intheightMeasureSpec)都是由父容传递过来的,父容器根据自己的measureSpec和子View的layoutParams和padding和margin计算子View的measureSpec

ViewGroup方法:

1. protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
    final int size = mChildrenCount;
    final View[] children = mChildren;
    for (int i = 0; i < size; ++i) {
        final View child = children[i];
        if ((child.mViewFlags &VISIBILITY_MASK) != GONE) {
            measureChild(child,widthMeasureSpec, heightMeasureSpec);
        }
    }
}

该方法测量所有的子View

2.protected void measureChild(View child, intparentWidthMeasureSpec,
        int parentHeightMeasureSpec) {
    final LayoutParams lp =child.getLayoutParams();

    final int childWidthMeasureSpec =getChildMeasureSpec(parentWidthMeasureSpec,
            mPaddingLeft + mPaddingRight,lp.width);
    final int childHeightMeasureSpec =getChildMeasureSpec(parentHeightMeasureSpec,
            mPaddingTop + mPaddingBottom,lp.height);

    child.measure(childWidthMeasureSpec,childHeightMeasureSpec);
}

该方法测量一个子View,调用子view.measure方法,子View的measureSpec计算方法getChildMeasureSpec

3. protected void measureChildWithMargins(View child,
        int parentWidthMeasureSpec, intwidthUsed,
        int parentHeightMeasureSpec, intheightUsed) {
    final MarginLayoutParams lp =(MarginLayoutParams) child.getLayoutParams();

    final int childWidthMeasureSpec =getChildMeasureSpec(parentWidthMeasureSpec,
            mPaddingLeft + mPaddingRight+ lp.leftMargin + lp.rightMargin
                    + widthUsed, lp.width);
    final int childHeightMeasureSpec =getChildMeasureSpec(parentHeightMeasureSpec,
            mPaddingTop + mPaddingBottom+ lp.topMargin + lp.bottomMargin
                    + heightUsed,lp.height);

    child.measure(childWidthMeasureSpec,childHeightMeasureSpec);
}

也是测量子View,这个方法考虑到padding和margin,ViewGroup是一个抽象类,没有

重写onMeasure方法,这是因为ViewGroup的子类具有不同的布局特性,每个子类的测量细节也不同,由它的子类,如LinearLayout,RelativeLayout去重写onMeasure方法

LinearLayout方法:

LinearLayout继承自ViewGroup

1. @Override
protected void onMeasure(intwidthMeasureSpec, int heightMeasureSpec) {
    if (mOrientation == VERTICAL) {
        measureVertical(widthMeasureSpec,heightMeasureSpec);
    } else {
       measureHorizontal(widthMeasureSpec, heightMeasureSpec);
    }
}

分为水平方向和竖直方向两种情况,下面看一下竖直方向

2. voidmeasureVertical(int widthMeasureSpec, int heightMeasureSpec) {

………

 

final int usedHeight = totalWeight == 0 ?mTotalLength : 0;
measureChildBeforeLayout(child, i, widthMeasureSpec, 0,
        heightMeasureSpec, usedHeight);


final int childHeight = child.getMeasuredHeight()

……

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值