目录
一.MeasureSpec
二.View的绘制流程
三.自定义View
1.MeasureSpec基础
(1)组成:MeasureSpec是一个32位int值,高2位代表SpecMode(测量模式),低30位代表SpecSize( 某种测量模式下的规格大小)。
(2)三种模式:
(图片来自厘米姑娘)
2.MeasureSpec和LayoutParams关系
顶级View(即DecorView):其MeasureSpec由窗口的尺寸和自身的LayoutParams决定
子View:MeasureSpec由父容器的MeasureSpec和自身的LayoutParams共同决定。
1.总的流程:measure->layout->draw
具体过程:
2.onMeasure:确定测量宽高,但是不是最终的宽高(layout中可以设置宽高,但是一般onMeasure中的测量宽高就是最终宽高)
(1)子View:通过measure()即可完成测量
注意:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec,heightMeasureSpec);
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
//分析模式,根据不同的模式来设置
if(widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST){
setMeasuredDimension(mWidth,mHeight);
}else if(widthSpecMode == MeasureSpec.AT_MOST){
setMeasuredDimension(mWidth,heightSpecSize);
}else if(heightSpecMode == MeasureSpec.AT_MOST){
setMeasuredDimension(widthSpecSize,mHeight);
}
}
(2)ViewGroup的measure:除了完成ViewGroup自身的测量外,还回去遍历调用子view的neasure方法
ViewGroup中没有重写onMeasure(),而是提供measureChildren()。
3.layout过程:确定View的最终宽高和四个顶点的位置
大致流程:从顶级View开始依次调用layout(),其中子View的layout()会调用setFrame()来设定自己的四个顶点(mLeft、mRight、mTop、mBottom),接着调用onLayout()来确定其坐标,注意该方法是空方法,因为不同的ViewGroup对其子View的布局是不相同的。
最终宽高:一般情况下为上一步的测量宽高,但是用户可以重写onLayout中确定最终宽高。如下代码会使最终宽高比测量宽高大100px
public void layout(int l,int t,int r,int b){
super.layout(l,t,r+100,b+100);
}
4.draw过程:绘制到屏幕
绘制顺序:
注意:
1.自定义View分类
注:
继承View需要重写onMeasure,使得其支持wrap_content
重写onDraw,使得其支持padding
2.自定义View步骤
(1)自定义属性,xml文件中指定,View的构造函数中得到属性组,在得到具体的属性做操作。
(2)重写onMeasure和onDraw对wrap_content和padding做特殊处理
3.注意事项