Android 自定义View知识点

自定义View知识点

自定义View我们需要了解View的绘制机制和ViewGroup的绘制机制,了解之后我们就可以在系统预留的方法里进行自定义View的工作了。

1、MeasureSpec

模式 说明
UNSPECIFIED 父容器不对View有任何限制,给它想要的任何尺寸。一般用于系统内部,表示一种测量状态。
EXACTLY 父容器已经检测出view的精确大小,这时候view的大小就是size所指定的值。它对应于LayoutParams中的match_parent和具体数值两种模式。
AT_MOST 父容器指定了一个可用大小,即size,子view的大小不能大于这个值,具体值要看vew的实现。它对应于LayoutParams中的wrap_content。

MeasureSpec是受到自身的LayoutParams和父容器的MeasureSpec共同影响的。

2、Measure

1、View的Measure过程

1.View调用onMeasure方法,onMeasure方法里调用了setMeasuredDimension方法,setMeasuredDimension方法又调用了getDefaultSize方法。

2.调用setMeasuredDimension方法,该方法是用来设置View的宽高的。

3.setMeasuredDimension方法调用了getDefaultSize方法,该方法根据传入的不同的MeasureSpec和size进行测量返回不同的测量结果。在AT_MOST和EXACTLY模式下,返回MeasureSpec.getSize方法返回的值,在UNSPEXIFIED方法里返回传入的大小值。根据上面的MeasureSpec表可知,对于直接继承View自定义的View而言,wrap_content和match_parent是一样的,所以我们要重写onMeasure方法。

4.getDefaultSize方法传入的参数调用了getSuggestedMinimumWidth()和getSuggestedMinimumHeight()方法。这两个方法会根据View是否有背景来返回测量的值。如果没有背景则返回mMinWidth或者mMinHeight,mMin的值是可以在View里设置的,通过setMinimumWidth或者setMinimumHeight即可设置;如果有背景则返回mMinWidth或者mMinHeight和mBackground.getMinimumWidth或mBackground.getMinimumHeight中的最大值。

2、ViewGroup的Measure过程

1.ViewGroup不只要测量自身,还要便利测量子元素的measure方法。ViewGroup里没有提供onMeasure方法,但是它有measureChildren方法。

2.在measureChildren方法里面它调用了getChildMeasureSpec方法。有意思的是我们可以在这张表里找到一个switch语句,里面有父View和子View测量模式最终返回的不同的结果,如图所示

父View测量模式 子View LayoutParams 最终测量模式
EXACTLY 具体值 EXACTLY
EXACTLY MATCH_PARENT EXACTLY
EXACTLY WRAP_CONTENT AT_MOST
AT_MOST 具体值 EXACTLY
AT_MOST MATCH_PARENT AT_MOST
AT_MOST WRAP_CONTENT AT_MOST
UNSPECIFIED 具体值 EXACTLY
UNSPECIFIED MATCH_PARENT UNSPECIFIED
UNSPECIFIED WRAP_CONTENT UNSPECIFIED

需要注意的是,当父容器的测量模式为AT_MOST时,子View的LayoutParams为WRAP_CONTENT,根据上图则可以发现子元素的测量模式也是AT_MOST,要解决这个问题需要在LayoutParams里制定以下默认的宽和高。

3、Layout

layout方法的作用是确定View的位置。
layout有四个参数,分别是l、t、r、b分带是View从左上右下相对其父容器的位置。layout方法会调用setFrame方法,而setFrame方法也有四个参数,正是layout方法穿进去的四个参数。调用setFrame方法后会调用onLayout方法,而onLayout方法是个空方法。需要我们根据不同的需求去实现。

4、Draw

draw的流程如下:
1、绘制 backgroud(drawBackground) ;
2、如果需要的话,保存canvas的layer,来准备fading ;
3、绘制view的content(onDraw方法);
4、绘制children(dispatchDraw方法);
5、如果需要的话,绘制fading edges,然后还原layer ;
6、绘制装饰器、比如scrollBar(onDrawForeground);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章