我爱编程

自定义View系列(1)自定义view

2018-05-25  本文已影响0人  薛定谔_没有猫
 之前对自定义View这部分读过很多文章,每次看完都认为自己掌握了如何自定义view,但每次动手实践时,就发现还是一窍不通,现在自己动手,记下心得。
 自定义View我们大部分时候只需重写两个函数:onMeasure()、onDraw()。onMeasure负责对当前View的尺寸进行测量,onDraw负责把当前这个View绘制出来。

1、onMeasure
onMeasure()函数,测量并设置我们自定义View的宽高。我们知道,在代码中。我们可以通过layout_width和layout_height两个属性来设置View的宽高,那么我们又为什么重写onMeasure函数。在xml布局文件中,我们的layout_width和layout_height参数可以不用写具体的尺寸,而是wrap_content或者是match_parent。其意思我们都知道,就是将尺寸设置为“包住内容”和“填充父布局给我们的所有空间”。这两个设置并没有指定真正的大小,可是我们绘制到屏幕上的View必须是要有具体的宽高的,正是因为这个原因,我们必须自己去处理和设置尺寸,其实View类中给出了默认的处理方法,但在某些特殊情况下,就需要我们重写OnMeasure函数,比如我们知道,在自己自定义的View中,如果不作处理,那么wrap_content和match_parent的效果是一样大,都是填充父布局剩余的空间,那么如何让wrap_content正常实现呢?就需要通过重写OnMeasure函数来实现。
下面是OnMeasure函数的原型
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
其中的参数widthMeasureSpec是什么意思?
其实MeasureSpec是父布局对子空间的一种测量要求,每个measurespec代表宽度或者高度的要求以及大小,也就是说一个measurespec包含size和mode。它有三种mode(模式)

①UNSPECIFIED:父View没有对子View施加任何约束。它可以是任何它想要的大小。
②EXACTLY:父View已经确定了子View的确切尺寸。子View将被限制在给定的界限内,而忽略其本身的大小,具体的数值如25dp,就属于EXACTLY,而match_parent也属于EXACTLY,因为父View的剩余大小是固定的。
③AT_MOST:子View的大小不能超过指定的大小,wrap_content就属于AT_MOST
那么我们自定义View时,可以在OnMeasure函数中定义默认的size,如果模式为AT_MOST,即wrap_content,我们就可以让view的大小为默认的size即可
接下来我们动手实践一下,写一个自定义view并重写OnMeasure函数

public class canvasview extends View {
    public canvasview(Context context) {
        super(context);
    }

    public canvasview(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }



    public canvasview(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width=getSize(widthMeasureSpec);
        int height=getSize(heightMeasureSpec);
        if(width<=height){
            height=width;
        }else {
            width=height;
        }
        setMeasuredDimension(width,height);
    }
    public int getSize(int measureSpec){
        int defaultsize=100;
        int measuresize=defaultsize;
        int size=MeasureSpec.getSize(measureSpec);
        int sizemode=MeasureSpec.getMode(measureSpec);
        if(sizemode==MeasureSpec.UNSPECIFIED){
            return defaultsize;
        }else if(sizemode==MeasureSpec.AT_MOST){
            measuresize=200;
        }else if (sizemode==MeasureSpec.EXACTLY){
            measuresize=size;
        }
        return measuresize;
    }
}

布局文件中设置宽高为wrap_content,可以看到效果,呈现出一个正方形。
好了,本篇就到这里,OnDraw函数的使用我会在后面的文章结合Path写出来。

上一篇 下一篇

猜你喜欢

热点阅读