绘制流程
自定义View需要经过流程measure,layout,draw,将View展示出来。 measure:测量view宽高 layout:确定子View的位置 draw:将View绘制到屏幕
为什么需要测量(onMeasure)?
xml布局中,wrap_content和match_parent只是对宽高的限制,并没有具体大小。所以需要测量确定大小,来自定View大小。
MeasureSpec封装了对View的布局要求。
MeasureSpec代表一个32位的int值,高2位表示SpecMode,低30位表示SpecSize
测量模式有三种:EXACTLY(固定尺寸),AT_MOST(当前View取得的最大尺寸),UNSPECIFIED(没有任何限制)
使用时mactch_parent对应EXACTLY,wrap_content对应AT_MOST
为什么需要布局(onLayout)?
对于自定义ViewGroup,需要通过重写onLayout方法来确定子View的位置。自定View可以不重写onLayout方法。
为什么要进行绘制(onDraw)?
绘制是在通过测量和布局后,在限制的范围内,绘制自己需要的图形。
自定义ViewGroup实例
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int childCount = getChildCount(); //获取子View数量
//遍历子View,最子View自身进行测量
for(int i = 0;i < childCount;i++){
View childAt = getChildAt(i);
measureChild(childAt,widthMeasureSpec,heightMeasureSpec);
}
}
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int width = 0;
int height = 0;
Log.d(TAG,"Befor l = "+l+" t = "+t+" r = "+r+" b = "+b);
for(int i = 0;i < getChildCount();i++){
View childView = getChildAt(i);
width = childView.getMeasuredWidth();
height = childView.getMeasuredHeight();
MarginLayoutParams layoutParams = (MarginLayoutParams) getLayoutParams();
switch (i){
case 0:
l = layoutParams.leftMargin;
t = getHeight() - height - layoutParams.bottomMargin;
break;
case 1:
l = getWidth() - width - layoutParams.leftMargin - layoutParams.rightMargin;
t = getHeight() - height - layoutParams.bottomMargin;
break;
}
r = l + width;
b = height + t;
Log.d(TAG,"after l = "+l+" t = "+t+" r = "+r+" b = "+b);
childView.layout(l,t,r,b);
}
}