`
luochuang
  • 浏览: 24048 次
  • 性别: Icon_minigender_1
  • 来自: 成都
最近访客 更多访客>>
社区版块
存档分类
最新评论

PerformMeasure

 
阅读更多

概述

 

总体流程

 

 

    private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
        if (mView == null) {
            return;
        }
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
        try {
            mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }
 

 

 

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

        if (forceLayout || needsLayout) {
            // first clears the measured dimension flag
            mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;

            resolveRtlPropertiesIfNeeded();

            int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key);
            if (cacheIndex < 0 || sIgnoreMeasureCache) {
                // measure ourselves, this should set the 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 the high 32 bits, no mask needed
                setMeasuredDimensionRaw((int) (value >> 32), (int) value);
                mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;
            }

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

 

 

 

measure 用来测量 View 的宽和高,它的流程分为View的measure流程和ViewGroup的measure流程,只不过ViewGroup的measure流程除了要完成自己的测量,还要遍历地调用子元素的measure()方法。

 

performTraversals会依次调用 performMeasure、 performLayout   performDraw

 

performMeasure中会调用measure方法,在measure方法中又会调用onMeasure方法,在onMeasure方法中则会对所有的子元素进行measure过程,这个时候measure流程就从父容器传递到子元素中了,这样就完成了一次measure过程。接着子元素会重复父容器的measure过程,如此反复就完成了整个View树的遍历。

 

View的Measure

 

 

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

 

ViewGroup, 它不只要测量自身,还要遍历地调用子元素的 measure()方法。ViewGroup 中没有定义 onMeasure() 方法,定义了 measureChildren()方法:

 

 

    protected void measureChild(View child, int parentWidthMeasureSpec,
            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);
    }
 

 

调用 child.getLayoutParams()方法来获得子元素的 LayoutParams 属性,

 

获取子元素的 MeasureSpec 并调用子元素的 measure()方法进行测量。

 

 

public static int getChildMeasureSpec(int spec, int padding, int
childDimension) {
 int specMode = MeasureSpec.getMode(spec);
 int specSize = MeasureSpec.getSize(spec);
 int size = Math.max(0, specSize - padding);
 int resultSize = 0;
 int resultMode = 0;
 switch (specMode) {
 case MeasureSpec.EXACTLY:
 if (childDimension >= 0) {
 resultSize = childDimension;
 resultMode = MeasureSpec.EXACTLY;
 } else if (childDimension == LayoutParams.MATCH_PARENT) {
 resultSize = size;
 resultMode = MeasureSpec.EXACTLY;
 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
 resultSize = size;
 resultMode = MeasureSpec.AT_MOST;
 }
 break;
 case MeasureSpec.AT_MOST:
 if (childDimension >= 0) {
 resultSize = childDimension;
 resultMode = MeasureSpec.EXACTLY;
 } else if (childDimension == LayoutParams.MATCH_PARENT) {
 resultSize = size;
 resultMode = MeasureSpec.AT_MOST;
 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
 resultSize = size;
 resultMode = MeasureSpec.AT_MOST;//1
 }
 break;
 case MeasureSpec.UNSPECIFIED:
 if (childDimension >= 0) {
 resultSize = childDimension;
 resultMode = MeasureSpec.EXACTLY;
 } else if (childDimension == LayoutParams.MATCH_PARENT) {
 resultSize = 0;
 resultMode = MeasureSpec.UNSPECIFIED;
 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
 resultSize = 0;
 resultMode = MeasureSpec.UNSPECIFIED;
 }
 break;
 }
 return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
}
 

 

根据父容器的 MeasureSpec 模式再结合子元素的 LayoutParams 属性来得出的 子元素的 MeasureSpec 属性。

 

如果父容器的 MeasureSpec 属性为 AT_MOST,子元素的 LayoutParams 属性为 WRAP_CONTENT,则子元素的MeasureSpec属性也为AT_MOST,它的SpecSize值为父容器的SpecSize 减去 padding 的值。

 

 

 

 

 

分享到:
评论

相关推荐

    Android视图的绘制流程(上) View的测量

    测量过程始于`ViewRootImpl`的`performTraversals`方法,它会调用`performMeasure`来测量根View。`performMeasure`进一步调用`View`的`measure`方法。尽管`measure`方法是final的,不允许子类直接重写,但其内部调用...

    Android移动应用开发相对布局RelativeLayout的特点.pdf

    这两者在绘制屏幕时,都会经历`performTraversals`、`performMeasure`、`performLayout`和`performDraw`等步骤,遍历整棵视图树,完成测量、布局和绘制的过程。 尽管`RelativeLayout`在某些情况下性能相对较慢,但...

    Android view面试专题.pdf

    - `performTraversals`是绘制流程的起点,它调用`performMeasure`,使用`MeasureSpec`确定View的大小。 - `MeasureSpec`包含尺寸模式(EXACTLY, AT_MOST, UNSPECIFIED)和大小值,指示View应如何测量自身。 - `...

    全面的Android view相关知识汇总整理

    - `performTraversals()`是绘制流程的起点,它会调用`performMeasure()`,传入两个MeasureSpec,用于确定View的大小。 - `measure()`过程根据父View的约束和自身的LayoutParams计算大小。 - `layout()`阶段,View...

    window和windowManager1

    这是Android视图树遍历的核心方法,包含了`performMeasure()`, `performLayout()`, 和 `performDraw()`等步骤,用于确定View的大小、位置以及绘制视图。 8. **LayoutParams**: `LayoutParams`是View在特定容器...

    Android View 布局流程(Layout)全面解析

    前言 上一篇文章,笔者详细讲述了View三...上一篇文章提到,三大流程始于ViewRootImpl#performTraversals方法,在该方法内通过调用performMeasure、performLayout、performDraw这三个方法来进行measure、layout、draw流

    Android View 测量流程(Measure)全面解析

    在`performTraversals()`中,我们看到`performMeasure()`被调用,传入了两个参数`childWidthMeasureSpec`和`childHeightMeasureSpec`。这两个参数是MeasureSpec对象,它们包含了父View对子View的尺寸要求。 ...

    Android View 绘制流程(Draw)全面解析

    当系统准备显示视图时,会依次调用`performMeasure`、`performLayout`和`performDraw`,来确定View的大小、位置和外观。 `performDraw`方法是绘制流程的起点。此方法内部会检查`mFullRedrawNeeded`标志,以确定是否...

Global site tag (gtag.js) - Google Analytics