看了之前自己写的两个自定义View的博客,鉴于决定要好好写博客,所以在此写篇讲述博客,因为那两篇自定义View的博客基本都是直接上代码,很多新手肯定不知道为什么这么写,为什么是重写onDraw之类的方法。
View就是视图,你所能看见的控件都是直接或者间接继承自它的,所谓的自定义View就是直接继承View或者间接继承(即继承TextView之类的)然后重新它的相关方法来完成自己需要的样子,自定义View是进阶必须会的,记住是必须。你们可以去看看View的结构,里面有很多方法,当然,我也不是大神,只是一个在那大神路上行走的一个菜B,所以咋们也没必要完全弄明白View里面的各个方法到底是干嘛的,有什么用,因为即使大神也不一定都知道,咋们只需要知道哪些方法是拿来干嘛的就够了,94那么鸡汁~
自定义View需要知道的主要是这几个方法:
1.onMeasure():改方法是用来测量View的大小的
2.onDraw():该方法是用来画View的
这么解释,自定义View需要的步骤是,咋们需要先知道你需要画的东西(View就是用canvas画出来的)多大(在onMeasure中测量),然后才能开始用画笔画(画这个操作是在onDraw方法中)。所以自定义View:先测量大小(重写onMearsure()方法),再画(重写onDraw()方法)。
我们先来看重写的onMeasure()方法,它的方法是这样的:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
这个方法有两个参数,widthMeasureSpec和heightMeasureSpec,Android系统有个类——MeasureSpec类,它里面包含了测量模式和测量的大小,所以这两个参数就是包含了宽和高的测量模式和测量大小,什么是测量模式呢?就是测量大小的方式,说白点就是怎么测大小,比如如果你设置了View的具体大小,那它就直接测View真实大小,如果设置View宽是match_parent,那么它就会测你父View的大小,大概就是这么个意思。测量好大小之后,我们在onMeasure方面里通过setMeasuredDimension(int w,int h)方法来设置大小生效。
那么具体怎么测大小呢?我们就需要从widthMeasureSpec和heightMeasureSpec里面提取测量模式和测量的大小了,可能细心点的人就会问了,尼玛,你不是说了里面包含了测量模式和测量的大小吗,为啥还要测量,吃饱了撑的啊,说实话,刚吃完午饭写这篇博客,我现在还真没吃饱~就特么四季豆盖饭,肉都不够吃,好TM惨,咳,扯远了,拉回来。为啥还要测量呢?因为里面确实包含了测量的大小,但是不一样,那个是系统帮我们测量的大小,不是我们自己测的,系统难道测不准?还要我们自己再测?那它有个屁用啊?不要急嘛,慢慢来呀,我给你一张纸,你给我画一头猪,画呀,恩,当然你画出来了,但是你特么画这么大干嘛?此时你就会说了:尼玛,你又没说具体画多大,我咋知道要画多大的。没错,就是这样,你自定义一个View,比如设置了宽度100dp,好办,系统一测很简单100dp,但是你特么给我来个wrap_content,我特么怎么知道具体是多大?但是此时系统还是会给你测,它不知道具体多大会给你默认测量大小为match_parent的长度,很明显不对啊,所以此时才需要自己测量了啊~懂了吧,还不懂?简单,自己百度吧,啊哈哈。比如设置了宽度100dp或者wrap_content这些都可以理解为测量模式。现在我们取出测量模式:
int wSpec = MeasureSpec.getMode(widthMeasureSpec);
int hSpec = MeasureSpec.getMode(heightMeasureSpec);
一个是宽的测量模式,一个是高的,测量模式有三个值:
1.EXACTLY:精确值模式,就是将宽高设为具体值的时或者match_parent时,比如上面的100dp,我说了那么系统测出来的就是跟我们这个值一样。
2.AT_MOST:最大值模式,就是设置为wrap_content时,根据内容的变化而变化,前提是不超过父控件给定的大小。
3.UNSPECIFIED:不定模式,就是不指定大小,View想多大就多大,基本只有自定义View才会用到。
onMeasure()方法分析完了,就是这样,所以我们需要根据不同的模式来进行测量View的大小,所以自定义View有测量大小这个步骤(在onMeasure()方法里进行)。
我们再看看重写的onDraw()方法:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
很简单,画布canvas一个参数,调用这个canvas进行绘画就可以了,这个方法比较简单,不做介绍了。
所以自定义View:重写onMeasure()方法测量大小->在onDraw()方法里画出即可(比如TextView就是画文字),本篇幅只做自定义View的讲述和方法结构分析,所以就不写案例了。之前有两篇自定义View(自定义进度条)的博文,虽然有点粗糙,想看案例的可以去看看,详细的自定义View案例会在后续博文中写出。啊,对了,还有自定义ViewGroup的分析也会在后续博文中写出。
补充:如果自定义View咋们是继承已有的比如TextView或者Button之类的View来实现自定义View,那么background,textsize之类的就不需要咋们自己定义了,因为我们所继承的View已经有了,除非不满意需要自己更改;那么如果直接自定义View继承自View,那么没有所谓的background和textsize之类的属性了,那么此时就需要我们自定义了,那么此时的步骤又是怎么的呢?
1.在res/values文件夹下面新建文件夹attrs.xml,此文件用于自定义属性比如背景色、字体大小等。
2.在我们自定义View的构造方法中获取这些自定义的属性并赋值给对应的属性。
具体方法在后面的代码篇中有涉及到~