protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec),measureHeight(heightMeasureSpec));
}
//需要调用自定义的measuredWidth和measureHeight方法,分别对宽//高进行重新定义,参数是宽高的MeasureSpec对象.MeasureSpec对象//中包含了测量的模式和测量值的大小.
private int measuredWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
result = 200;// 当不为精确模式时都要给个默认值,理由上面已说明
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);// 不能超过父控件的最大允许尺寸,特别的,如果指定wrap_content,则需要取出我们指定的大小和SpecSize中最小的一个来作为最后的测量值.
}
}
return result;
}
//measureHeight的方法几乎与上面一样
4.验证:
(1)在布局文件中,先指定确定的宽高属性为100dp(320*480分辨率的屏幕),效果如下:
(2)当指定宽高的属性为match_parent时 ,效果为:
(3)当指定宽高属性为wrap_content时,如果不重写onMeasure方法,那么系统就不知道该使用多大的尺寸,因此会默认填充整个父布局,所以重写onMeasure方法的目的是给View一个wrap_content属性下的默认大小,所以当设定默认大小为200时,指定wrap_content属性时,view就获得了一个默认的200px值,而不再是填充父布局了.
package com.itanelse.viewmeasure.views;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;
public class MyView extends TextView {
public MyView(Context context) {
this(context, null);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measuredWidth(widthMeasureSpec), measuredHeight(heightMeasureSpec));
}
private int measuredWidth(int widthMeasureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
}else{
result = 100;//设定默认值
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);//区两者中的最小值作为最后的测量值
}
}
return result;
}
private int measuredHeight(int heightMeasureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(heightMeasureSpec);
int specSize = MeasureSpec.getSize(heightMeasureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
}else{
result = 100;//设定默认值
if (specMode == MeasureSpec.AT_MOST) {
result = Math.min(result, specSize);//区两者中的最小值作为最后的测量值
}
}
return result;
}
}
1.当测量好一个view之后,我们就可以重写onDraw(Canvas canvas)方法,并在Canvas对象上来绘制所需要的图形.而在其他地方需要使用代码来创建一个Canvas对象.代码如下:
Canvas canvas = new Canvas(bitmap)
canvas.drawBitmap(bitmap1,0,0,null);
Canvas mcanvas = new Canvas(bitmap1);
mcanvas.drawxxx
通过这个mcanvas将绘制效果作用在bitmap1上,在刷新view的时候,就会发现通过onDraw方法绘制出来的bitmap1已经发生了变化,这就是bitmap1承载了mcanvas上所进行的绘图操作,我们其实并没有绘制在mcanvas画布上,而是通过改变bitmap,然后让view重绘,从而改变之后的bitmap
viewgroup通常情况下不需要绘制,因为它本身就没有需要绘制的东西,如果不是指定可viewgroup的背景颜色,那么onDraw方法不会被调用.但是viewgroup会使用dispatchDraw方法来绘制其子view,其过程同样是遍历所有的子view,并调用子view的绘制方法来完成绘制工作.