解析:
在Android 中Window对象通常由PhoneWindow来实现。
PhoneWindow将一个DecorView设置为整个应用窗口的根View。DecorView作为窗口界面的顶层视图,封装了一些窗口操作的通用方法。
另外:
看图片就知道,DecorView将屏幕分成两部分,第一个是TitleView,另外一个ContentView,它是一个Id为content的FragmentLayout。也就是这样理解。DecorView是一个顶层View,一般情况下它内部会包含一个竖直方向的LinearLayout,所以就分成了TitleView跟ContentView.
那么,就知道指定布局的方法不叫做setview而是setContentView了。
然后介绍代码中,当程序中onCreate(),调用setContentView()方法后,ActivitymanagerService会回调onResume()方法,此时系统就把整个DecorView添加到PhoneWindow中,并且显示出来,最后完成界面的绘制。
问题的由来 —->如果我们要去画一个图形,就必须知道它的大小和位置。同理,告诉andriod系统应该画一个多大的View,这个过程就要在onMeasure()方法中进行。
讲起onMeasure()方法又引出了一个相关的类——>MeasureSpec
类。
MeasuseSpec :测量规格
- SpecMode: 测量模式
UNSPECIFIED–父容器不对View有任何限制。(少用)
EXACTLY—父容器检测出View所需要的精确大小,这个时候View的最终大小由SpecSize所指定的值来确定。(对应于match_parent和具体数值这两个模式)。
AT_MOST–父容器指定了一个SpecSize的值,View得大小不能超过这个值。(对应于wrap_content)
注意:View类默认的onMeasure()方法只是支持EXACTLY模式,所以如果自定义控件时候不重写onMeause()方法的话,就只能用EXACTLY模式了。如果想让自定义View支持wrap_content属性,那么就要重写onMeasure()方法。
2. SpecSize:测量大小
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
点击这个super.onMeasure();可以看出—————
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
可以看出系统最终调用 setMeasuredDimension()方法,所以我们重写这个onMeasure()方法时候,就要把测量出的参数设置给setMeasuredDimension();
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec), measuredHeight(heightMeasureSpec));
}
这个是重写后的代码,可以看出,我自定义了measureWidth(widthMeasureSpec)方法和measuredHeight(heightMeasureSpec)
接下来 :
通过判断测量模式,给出不同的测量值,当specMode为EXACTLY时候,使用指定specSize即可,当是AT_MOST模式,则需要取出我们指定的大小与specSize中最小的一个来作为最后的测量值,measureWidth()方法代码如下—>基本上模板代码。
private int measureWidth(int widthMeasureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
}else{
result=200;
if(specMode==MeasureSpec.AT_MOST){
result=Math.min(result, specSize);
}
}
return result;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GRAY);
int width = getWidth();
int height = getHeight();
Log.e(TAG, "width : " + width + " height : " + height);
}
Log 输出查看
05-04 03:56:19.597: E/MainActivity(2425): width : 200 height : 200