match_parent就是要利用父View给我们提供的所有剩余空间,而父View剩余空间是确定的,也就是这个测量模式的整数里面存放的尺寸。
固定尺寸(100dp)--->EXACTLY.用户自己制定了尺寸大小,我们就不用再去干涉了,当然是以指定的大小为主。
父容器已经为子容器设置了尺寸,子容器应当服从这些边界,不论子容器想要多大的空间。
我们想要将大小设置为包裹我们的View内容,那么尺寸大小就是父View给我作为参考的尺寸,至于不超过这个尺寸就可以啦。具体尺寸就根据我们的需求去设定。
3.UNSPECIFIED:这种测量模式多用在ScrollView中,或者系统内部调用;当前的尺寸就是当前View应该取的尺寸;父容器对于子容器没有任何限制,子容器想要多大就多大。
举个例子 以绘制一个 矩形为例1.在 res/values/styles.xml 文件(如果没有就需要新建),里面声明一个我们自定义的属性:
<declare-styleable > <!--声明我们的属性,名称为 default_size,取值类型为尺寸(dp,dx等)--> <attr format="dimension"/></declare-styleable>
2.在我们自定义View里面吧我们自定义的属性值取出来,在构造函数中,有个AttributeSet的属性,我们需要用它来帮我们把布局里面的属性取出来。
private int defaultSize;public Views(Context context, AttributeSet attrs) { super(context, attrs); //第二个参数就是我们在styles.xml文件中的<declare-styleable>标签 //即属性集合的标签,在R 文件中名称为 R,styleable+name TypedArray a=context.obtainStyledAttributes(attrs, R.styleable.RectangleView); //第一个参数为属性几个里面的属性,R文件名称:R。styleable+属性集合名称+下划线+属性名称 //第二个参数为,如果没有设置这个属性,则设置的默认的值 defaultSize=a.getDimensionPixelSize(R.styleable.RectangleView_default_size,100); //最后记得将TypedArray对象回收 a.recycle();}
3.完成的代码如下:
public class RectangleView extends View { public RectangleView (Context context) { super(context); } private int defaultSize; public RectangleView (Context context, AttributeSet attrs) { super(context, attrs); //第二个参数就是我们在styles.xml文件中的<declare-styleable>标签 //即属性集合的标签,在R 文件中名称为 R,styleable+name TypedArray a=context.obtainStyledAttributes(attrs, R.styleable.RectangleView); //第一个参数为属性几个里面的属性,R文件名称:R。styleable+属性集合名称+下划线+属性名称 //第二个参数为,如果没有设置这个属性,则设置的默认的值 defaultSize=a.getDimensionPixelSize(R.styleable.RectangleView_default_size,100); //最后记得将TypedArray对象回收 a.recycle(); } private int getMySize(int defaultSize,int measureSpec){ int mySize=defaultSize; //取测量模式 int mode=MeasureSpec.getMode(measureSpec); //取测量长度 int size=MeasureSpec.getSize(measureSpec); switch (mode){ //如果没有指定大小,就设置为默认大小 case MeasureSpec.UNSPECIFIED: mySize=defaultSize; break; //如果测量模式是最大取值size //我们将大小取最大值,你也可以取其他值 case MeasureSpec.AT_MOST: mySize=size; break; //如果是固定的大小,那就不要去改变它 case MeasureSpec.EXACTLY: mySize=size; break; } return mySize; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width=getMySize(defaultSize,widthMeasureSpec); int heigth=getMySize(defaultSize,heightMeasureSpec); if (width<heigth){ heigth=width; }else{ width=heigth; } setMeasuredDimension(width,heigth); } @Override protected void onDraw(Canvas canvas) { //调用父View的onDraw函数,因为View这个类帮我们实现了一些 //基本的绘制功能,拨入绘制背景颜色,背景图片等。 super.onDraw(canvas); //也可以是 getMeasuredHieght()/2,因为这个例子中我们已将宽高设置相等了 int r=getMeasuredWidth()/2; // 绘制的元素位置 相对于当前view //圆心的横坐标为当前View的View左边起始位置+半径 int centerx=r; //圆心的纵坐标表为当前的View的顶部起始位置+半径 int centery =r; //设置画笔 @SuppressLint("DrawAllocation") Paint paint=new Paint(); //设置画笔颜色 paint.setColor(Color.GREEN); //开始绘制 canvas.drawCircle(centerx,centery,r,paint); }}
拓展:关于 onMeasure ,Android已经封装了 resolveSize 方法,只需要调用该方法就可以自动为我们选择合适的值
姓名:
年龄:
电话: