简单说说自己对自定义view的onMeasure的理解

在学习自定义view 的时候,一直不懂这个东,新手,总感觉这个很难,于是带着猜想写下这篇文章,通过测试来谈谈自己对onMeasure()方法的理解

下面是具体的测试代码

package com.mingrisoft.myapplication;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import static android.content.ContentValues.TAG;
/**
 * Created by fang on 2018/3/22.
 */
public class myView extends View {
    public static String TAG="test";
    int width;
    int height;
    int radius=100;
    public myView(Context context) {
        this(context,null);
    }
    public myView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }
    public myView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
    private void init() {
        Paint paint =new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(1f);
        paint.setColor(getResources().getColor(R.color.colorAccent));
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width1=getEvaluateMeasure(widthMeasureSpec);
        int height1=getEvaluateMeasure(heightMeasureSpec);
        setMeasuredDimension(width1,height1);
    }
    private int getEvaluateMeasure(int MeasureSpec) {
        int model= View.MeasureSpec.getMode(MeasureSpec);
        int size=View.MeasureSpec.getSize(MeasureSpec);
        int value = 0;
        if(model== View.MeasureSpec.EXACTLY){
            Log.d(TAG, "getEvaluateMeasure:EXACTLY下:"+size);
        }else if(model==View.MeasureSpec.AT_MOST){
            Log.d(TAG, "getEvaluateMeasure: AT_MOST下"+size);
        }
        return value;
    }
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
    }

下面是我对测试的过程的回顾与总结
1 .首先为了验证我的猜测,做了以下测试

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<com.mingrisoft.myapplication.myView
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
</LinearLayout>

首先我考虑当view的布局为match_parent时,MeasureSpec对应的mode为AT_MOST
时,由于这样会进行查找父集的数据,而linearLayout为match_parent,就会接受他的父集的宽高的设定,最终会查找到window,也就是这个屏幕的大小,所以这样的设置,MeasureSpec.getSize();得到的最终值为屏幕大小。

这里写图片描述
下面进行第二组测试

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<com.mingrisoft.myapplication.myView
    android:layout_width="200dp"
    android:layout_height="200dp" />
</LinearLayout>

按照之前的分析,子项布局采用了绝对的数值,那么这时MeasureSpec对应的模式为EXACTLY,也就是说这样的话,MeasureSpec.getSize(int,int)得到的就是布局的大小。即400px
这里写图片描述

第四组测试

<LinearLayout
    android:layout_width="100dp"
    android:layout_height="100dp">
<com.mingrisoft.myapplication.myView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
</LinearLayout>

子布局采用的是wrap_content,对应的MeasureSpec对应的模式为AT_MOST,按照之前所讲,会继续查找父布局,得到的最终的MeasureSpec.getMode(int)得到的值就位父布局的大小
即MeasureSpec.getMode(int)==200px;
这里写图片描述
第五组测试用例

<LinearLayout
    android:layout_width="100dp"
    android:layout_height="100dp">
<com.mingrisoft.myapplication.myView
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
</LinearLayout>

根据之前的分析,查找父集的大小,当为确定值时,子项布局就会得到最终的大小,
也即是MeasureSpec.getmode(int)==EXACTLY时,得到的MeasureSpec.getSize(int)就是200px
这里写图片描述
第六组测试

<LinearLayout
    android:layout_width="100dp"
    android:layout_height="100dp">
<com.mingrisoft.myapplication.myView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
</LinearLayout>

不用说的。在MeasureSpec.getMode(int)==AT_MOST下,MeasureSpec.getSize(int)==200px
这里写图片描述

扫描二维码关注公众号,回复: 1805902 查看本文章

总结如下:
这里写图片描述
总结:
如果发现子视图为matchParent,或wrapContet就会将父集的宽高赋值给子视图,当父集也为matchParent或wrapcontent时(父集为这个值时,也会接受到父集的父集的宽高),这样的效果会在整个节点数中向下传递。

在此基础上我再次测试数据
我在里面重写了onDraw(Canvas);来测试数据的正确性
给出所有的代码

package com.mingrisoft.myapplication;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import static android.content.ContentValues.TAG;

/**
 * Created by fang on 2018/3/22.
 */

public class myView extends View {
    public static String TAG="test";
    int width;
    int height;
    int radius=100;
    public myView(Context context) {
        this(context,null);
    }
    public myView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }
    public myView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        Paint paint =new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(1f);
        paint.setColor(getResources().getColor(R.color.colorAccent));
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//            MeasureSpec.getMode(widthMeasureSpec);
//        Log.d(TAG, "测量宽度"+getMeasuredWidth()+"测量高度"+getMeasuredHeight());
        int width1=getEvaluateMeasure(widthMeasureSpec);
        int height1=getEvaluateMeasure(heightMeasureSpec);
        // Log.d(TAG, "width1="+width1+"height1="+height1);
        setMeasuredDimension(width1,height1);
    }
    private int getEvaluateMeasure(int MeasureSpec) {
        int model= View.MeasureSpec.getMode(MeasureSpec);
        int size=View.MeasureSpec.getSize(MeasureSpec);
        int value = 0;
        if(model== View.MeasureSpec.EXACTLY){
             value=size;//按照之前的分析,EXACTLY时,获得的是父集的大小
            Log.d(TAG, "getEvaluateMeasure:EXACTLY下:"+size);
        }else if(model==View.MeasureSpec.AT_MOST){
              value=radius*2;//当是AT_MOST时,及采用的布局时wrap_content,这是我们就要根据view的大小给出确定的值
            Log.d(TAG, "getEvaluateMeasure: AT_MOST下"+size);
        }
        return value;
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint=new Paint();
        paint.setColor(getResources().getColor(R.color.colorPrimary));
        paint.setTextSize(20f);
        Path path=new Path();
        path.addCircle(getWidth()/2,getHeight()/2,radius, Path.Direction.CCW);
        canvas.drawPath(path,paint);
    }
}

其他的都没变什么,在通过MeasureSpec的判断时,当mode==MeasureSpec.EXACTLY执行默认,但是当mode==MeasureSpec.AT_MOST时,我们采用的是绘制图像的大小,并在调用setMeasureDimention(int,int);将值传入,并在onDraw()中进行圆的绘制

下面是测试的xml文件

<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
<com.mingrisoft.myapplication.myView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
</LinearLayout>

按照以往的方式,MeasureSpec.getmode(int)==ATMOST.MeasureSpec.getSize(int)==window大小,但是我们在MeasureSpec.getmode(int)==ATMOST时,做出判断,宽度为2*radius,这使得圆会出现在屏幕的左上方.因为宽度就为200px;
这里写图片描述
如果不信,你可以尝试将MeasureSpec.getmode(int)==ATMOST的判断value=size;圆会出现在屏幕的中间.

测试二

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<com.mingrisoft.myapplication.myView
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
</LinearLayout>

结果:
这里写图片描述

测试三

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">
<com.mingrisoft.myapplication.myView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
</LinearLayout>

这里写图片描述

之后的数据就不测试了,也就说自己的猜想是正确的,
同样也看出,在setMeasureDimention(int,int);的参数会影响到width和height,这样的话才使得我们使用getWidth();得出正确的值。

注:本人水平有限,如自己的理解是错误的,请指正,不希望自己把被人带坑里
本章都是自己的测试得出的结论,错误请谅解。

猜你喜欢

转载自blog.csdn.net/qq_37657081/article/details/79661789