View[0] measure

本文详细解析了MeasureSpec的概念、生成过程及其在视图测量中的作用。通过理解MeasureSpec的三种模式:EXACTLY、AT_MOST 和 UNSPECIFIED,以及这些模式与布局参数(LayoutParams)之间的转换关系,帮助开发者更好地掌握自定义View和ViewGroup时的测量流程。

【参考链接】

 

我们在写布局文件的时候,是在设置LayoutParams,共有3种模式:

match_parentwrap_contentdimens

3种模式表达了我们希望给自己的View设置的宽度高度

 

但是,系统在进行测量measure()的时候,传进来的数据类型并不是LayoutParams,而是MeasureSpec

1.      这个MeasureSpec是什么

MeasureSpec是一个32位的int值,其中高2位代表Mode,低30位代表SizeMode主要有3类:EXACTLYAT_MOSTUNSPECIFIED。可以通过如下方式解析一个MeasureSpec

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
       int
widthSize =MeasureSpec.getSize(widthMeasureSpec);

       int
heightMode=MeasureSpec.getMode(heightMeasureSpec);
       int
heightSize=MeasureSpec.getSize(heightMeasureSpec);

//        //可以通过如下方式来创建一个MeasureSpec
//       int spec = MeasureSpec.makeMeasureSpec(widthSize, widthMode);

 

2.      MeasureSpec是怎么来的

对于DecorView

MeasureSpecmodeEXACTLYsize是窗口宽高

\frameworks\base\core\java\android\view\ViewRoot.java

private int getRootMeasureSpec(int windowSize, int rootDimension) {
   
int measureSpec;
    switch
(rootDimension) {

   
case ViewGroup.LayoutParams.MATCH_PARENT:
       
// Window can'tresize. Force root view to be windowSize.
       
measureSpec =MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
       break;
    case
ViewGroup.LayoutParams.WRAP_CONTENT:
       
// Window canresize. Set max size for root view.
       
measureSpec =MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
       break;
    default
:
       
// Window wants tobe an exact size. Force root view to be that size.
       
measureSpec =MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
       break;
   
}
   
return measureSpec;
}

 

对于子View

系统把我们在布局文件中设置的LayoutParams和父ViewMeasureSpec进行计算,生成新的MeasureSpec,传递给自己的measure()方法

\frameworks\base\core\java\android\view\ViewGroup.java

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) {
   
// Parent has imposed an exact size onus
   
case MeasureSpec.EXACTLY:
       
if (childDimension >= 0) {
           resultSize = childDimension
;
           
resultMode =MeasureSpec.EXACTLY;
       
} else if (childDimension ==LayoutParams.MATCH_PARENT) {
           
// Child wants tobe our size. So be it.
           
resultSize = size;
           
resultMode =MeasureSpec.EXACTLY;
       
} else if (childDimension ==LayoutParams.WRAP_CONTENT) {
           
// Child wants todetermine its own size. It can't be
           // bigger than us.
           
resultSize = size;
           
resultMode =MeasureSpec.AT_MOST;
       
}
       
break;

   
// Parent has imposed a maximum size onus
   
case MeasureSpec.AT_MOST:
        
if (childDimension >= 0) {
           
// Child wants aspecific size... so be it
           
resultSize =childDimension;
           
resultMode =MeasureSpec.EXACTLY;
       
} else if (childDimension ==LayoutParams.MATCH_PARENT) {
           
// Child wants tobe our size, but our size is not fixed.
           // Constrain child to not be bigger than us.
           
resultSize = size;
           
resultMode =MeasureSpec.AT_MOST;
       
} else if (childDimension ==LayoutParams.WRAP_CONTENT) {
            
// Child wants to determine its ownsize. It can't be
           // bigger than us.
           
resultSize = size;
           
resultMode =MeasureSpec.AT_MOST;
       
}
       
break;

   
// Parent asked to see how big we wantto be
   
case MeasureSpec.UNSPECIFIED:
       
if (childDimension >= 0) {
           
// Child wants aspecific size... let him have it
           
resultSize =childDimension;
           
resultMode =MeasureSpec.EXACTLY;
       
} else if (childDimension == LayoutParams.MATCH_PARENT){
           
// Child wants tobe our size... find out how big it should
           // be
           
resultSize = 0;
           
resultMode =MeasureSpec.UNSPECIFIED;
       
} else if (childDimension ==LayoutParams.WRAP_CONTENT) {
           
// Child wants todetermine its own size.... find out how
           // big it should be
           
resultSize = 0;
           
resultMode =MeasureSpec.UNSPECIFIED;
       
}
       
break;
   
}
   
return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
}

 

转换关系可以用下表表示

 


 

match_parent

wrap_content

childDimen

AT_MOST

parentSize

AT_MOST

parentSize

AT_MOST

parentSize

EXACTLY

childDimen

EXACTLY

parentSize

EXACTLY

parentSize

AT_MOST

parentSize

EXACTLY

childDimen

 

3.      所以系统并没有直接采用我们的LayoutParams,而是转换成了MeasureSpec,这个转换造成了什么影响呢?

从上面DecorView可以知道,最上面的MeasureSpecmodeEXACTLY,所以,在MeasureSpec向下传递的过程中

如果下面的ViewLayoutParamsmatch_parent,那么其MeasureSpecmode就会保持为EXACTLY,并且sizeparentSize

 

match_parent

wrap_content

childDimen

AT_MOST

parentSize

AT_MOST

parentSize

AT_MOST

parentSize

EXACTLY

childDimen

EXACTLY

parentSize

EXACTLY

parentSize

AT_MOST

parentSize

EXACTLY

childDimen

 

但是,如果某个ViewLayoutParamswrap_content,则其MeasureSpecmode就会变成AT_MOST。并且即使下下面的ViewLayoutParamsmatch_parent

MeasureSpec也只能是AT_MOST了。

 

match_parent

wrap_content

childDimen

AT_MOST

parentSize

AT_MOST

parentSize

AT_MOST

parentSize

EXACTLY

childDimen

EXACTLY

parentSize

EXACTLY

parentSize

AT_MOST

parentSize

EXACTLY

childDimen

 

 

match_parent

wrap_content

childDimen

AT_MOST

parentSize

AT_MOST

parentSize

AT_MOST

parentSize

EXACTLY

childDimen

EXACTLY

parentSize

EXACTLY

parentSize

AT_MOST

parentSize

EXACTLY

childDimen

 

所以,虽然LayoutParams表达了我们的期望,但是系统并没有完全满足我们的期望,还是使用转换成的MeasureSpec来测量宽高。

 

4.      那么我们要如何使用这个MeasureSpec呢?

从上表可知,

如果LayoutParamsmatch_parent,则MeasureSpecsize就是parentSize。如果LayoutParamschildDimen,则MeasureSpecsize就是ChildDimen。这两个值是符合跟父View一样大小/指定大小的语义的。

并且此时MeasureSpecmode都是EXACTLY,所以当MeasureSpecmodeEXACTLY时,我们可以直接使用MeasureSpecsize作为measuredDimension

 

而当LayoutParamswrap_content时,MeasureSpecmodeAT_MOST,并且valueparentSize。这个时候我们可以根据自己的测量/布局想法,计算出长宽,设置成measuredDimension(实际是取跟parentSize比较的较小值)。

 

总结一下就是,在onMeasure()

如果MeasureSpecmodeEXACTLY,则可以直接使用MeasureSpecsize作为measuredDimension,否则再根据自己的需要计算长宽。

 

resolveSize()

按照上面的思路,在自定义View的时候,我们只需要计算AT_MOST时的长宽

所以系统为我们提供了resolveSize()方法,将AT_MOST时的长宽传进去就可以得到所有情况时的长宽,这可以方便我们少些很多代码。

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        super.onMeasure(widthMeasureSpec,heightMeasureSpec);

       //
假设AT_MOST时的长宽想要为300300//实际需要根据自己的测量/布局规则来计算
       
setMeasuredDimension(
               resolveSize(
300, widthMeasureSpec),
               
resolveSize(300, heightMeasureSpec)
        )
;

   
}

 

\frameworks\base\core\java\android\view\View.java

public static int resolveSize(int size, int measureSpec) {
   
int result = size;
    int
specMode =MeasureSpec.getMode(measureSpec);
    int
specSize =  MeasureSpec.getSize(measureSpec);
    switch
(specMode) {
   
case MeasureSpec.UNSPECIFIED:
       result = size
;
       break;
    case
MeasureSpec.AT_MOST://将计算大小和parentSize进行比较,取较小值
       
result =Math.min(size, specSize);
       break;
    case
MeasureSpec.EXACTLY:
       result = specSize
;
       break;
   
}
   
return result;
}

 

measureChildren()

在自定义ViewGroup的时候,重写onMeasure()时,还需要先对子View进行measure。系统也为ViewGroup提供了measureChildren()等方法。

protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec)

protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec)

 

此外,并不是在performTraversal()measure()就只执行一次

都是看各自的实现的,比如说LinearLayoutmeasure()就会进行两次。



内容概要:本文介绍了一种用于电磁暂态(EMT)研究的第四类全变流器型风力发电系统的通用Simulink仿真模型,旨在构建一个能够准确反映实际风电系统动态特性的简化通用模型。该模型涵盖了风力机、传动链、发电机、全功率变流器及其控制策略等关键组成部分,重点突出系统在电网故障、风速波动等复杂工况下的动态响应能力,适用于风电并网电磁暂态分析、新型电力系统稳定性评估及高比例可再生能源接入场景的研究。模型设计兼顾准确性与仿真效率,便于研究人员快速搭建和调试,推动风电系统建模与控制技术的发展; 适合人群:具备一定电力系统理论基础和MATLAB/Simulink仿真能力,从事新能源发电、电力电子变换、风电并网控制及相关方向的研究生、科研人员及工程技术人员; 使用场景及目标:①开展风电系统在电网扰动下的电磁暂态仿真分析;②研究全功率变流器风电机组的动态行为与控制特性;③支撑新型电力系统中高渗透率风电接入的稳定性与电能质量评估,服务于学术研究、课程教学与工程项目前期仿真验证; 阅读建议:建议读者结合文中提供的模型结构与参数设置,在Simulink环境中动手复现并调试仿真模型,通过设置不同运行工况(如三相短路、低电压穿越、风速突变等)观察系统响应,深入理解全变流器风电机组的建模方法、控制逻辑与动态特性,进而拓展应用于更复杂的多机并网或综合能源系统仿真场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值