自定义View三大流程理论篇

自定义View三大流程理论篇

以下介绍了自定义View的相关理论知识,具体实操见下一篇。

自定义View理论篇之onMeasure

Measure是测量的意思,顾名思义这个函数主要是用来设置我们自定义的View大小的。或许你可能会疑惑:我们在Xml文件中不是定义了大小了吗,为什么还需要再次测量,我们的 layout_widthlayout_height 参数是可以不用传递具体尺寸的,例如 wrap_contentmatch_parentmatch_parent最终会以父View提供的可用尺寸作为具体尺寸,我们主要处理的是wrap_content的情况。

onMeasure

先来看一下onMeasure函数的原型protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

onMeasure函数是在被父View调用measure函数之后的一个回调。从onMeasure函数的原型中可以看到两个参数,这两个参数是父容器在调用measure函数时传来的,代表了父容器推荐的当前View的大小,也就是说父容器希望当前View的一个尺寸,当然仅是推荐并非一定按照这个尺寸。widthMeasureSpec和heightMeasureSpec封装了尺寸的模式和大小,通常我们会根据测量模式再根据我们的需要再进一步计算View的实际大小下面展开来说。

MeasureSpec

MeasureSpec翻译过来就是测量规格的意思,它是View的一个内部类,主要用来获取测量模式和尺寸信息。继续上边说的widthMeasureSpec和heightMeasureSpec,正它们内部封装了两个信息

第一个就是测量模式,测量模式分为如下三种:

1、MeasureSpec.EXACTLY

这个挺好理解的,从字面意思就是"精确地",也就是说这个值是一个确定的值,当我们在xml中使用特定单位dp及其他单位或者使用match_parent时,传递过来的这个Mode就是MeasureSpec.EXACTLY。

2、MeasureSpec.AT_MOST

当我们在xml中使用wrap_content的时候就会是AT_MOST模式。也就是我们需要将当前的View

3、MeasureSpec.UNSPECIFIED

这个模式很特殊,通常只有在配合ScrollView控件时才会出现这个,我个人通常把这个模式和AT_MOST一起处理,当模式是这两种的时候直接将内容的大小,也就是所有子View的大小设置为当前View的大小。

测量模式的获取:

int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);

第二个就是尺寸:

尺寸也就是父容器建议我们使用的尺寸大小,我们在上边说过了这个尺寸仅仅是建议,具体会在下文提到。

尺寸的获取:

int w = MeasureSpec.getSize(widthMeasureSpec);
int h = MeasureSpec.getSize(heightMeasureSpec);

最后我们通过setMeasuredDimension(w, h)函数就可以设置当前View的一个确定了的宽和高。

如果我们想要自己定义一个类似于widthMeasureSpec的值可以通过MeasureSpec.makeMeasureSpec(size,mode)来创建。或者你可以了解一下它的组成原理然后自己计算也是可以的。

onMeasure的通常用法

在onMeasure中我们通常根据具体业务和需要计算出自己的大小然后告诉上一级的ViewGroup,如果我们也是一个ViewGroup那么就需要在onMeasure中对自己内部的子View进行measure,也就是调用子View的measure函数,也就是对子View进行测量,这是子View的onMeasure会被调用。依次呈递归调用,完成整个树结构的解析。

onMeasure的调用时机

onMeasure函数是在View的measure函数被调用时的一个回调,这个measure通常是上一级ViewGroup来完成的。通俗理解这个onMeasure就是上一级ViewGroup给了我们一个尺寸说你看看行不行,要是不行你就自己计算出来一个完事交给我。这个很好理解,因为上一级的ViewGroup是不应该对子View的大小做过分干涉的,如果对下一级的View进行过分干涉就会产生某种程度上的耦合。

在onMeasure之后调用getMeasuredWidth和getMeasuredHeight就有值了。

自定义View之onLayout理论篇

通常情况下我们只有在继承自ViewGroup的时候才会重写这个方法,也是必须要重写的,这个方法要做的事情就是将自己内部的子View进行摆放,具体如何摆放需要根据自己的需求,例如LinearLayout可以垂直和横向。
我们来看一下onLayout函数的原型:protected void onLayout(boolean changed, int l, int t, int r, int b)
参数中的l、t、r、b分别指代的是已经确定了的当前View的Left、Top、Right、Bottom(这个在基础篇已经说过)。
在这里我们需要对所有子View进行摆放,也就是调用子View的layout函数。

onLayout的调用时机

onLayout是在onMeasure函数之后调用的,在onMeasure确定View的大小后,进入到onLayout进行对子View的布局。还记得我们当时在onMeasure说过,在onMeasure参数中的宽高是推荐的,而在onLayout函数中尺寸是已经确定了的最终尺寸。

在onLayout之后调用getWidth和getHeight就有值了。

自定义View之onDraw理论篇

这个并没有什么要说的,主要就是一些绘图内容了,根据自己的需求进行绘制即可。绘图涉及到的东西有很多这里不展开来说了。这个函数是比起上边两个最后被调用的。
这里要说的是继承自ViewGroup后onDraw方法不会被回调,具体如下:

1)ViewGroup默认情况下,会被设置成WILL_NOT_DRAW,这是从性能考虑,这样一来,onDraw就不会被调用了。
2)如果我们要重要一个ViweGroup的onDraw方法,有两种方法:
1,在构造函数里面,给其设置一个颜色,如#00000000。
2,在构造函数里面,调用setWillNotDraw(false),去掉其WILL_NOT_DRAW flag。

最后

上边一堆文字描述,有可能说的不是很清楚,下图是描述View的持有关系以及基本的调用顺序。

图中的xxx表示linear1的上一级View。

posted @ 2019-08-29 17:01  QyLost  阅读(173)  评论(0)    收藏  举报