自感不会“自定义view”的安卓开发总是萌小白,今天进行一下基础的View的流程进行总结。虽然,网上有很多这些文章,但是自己想再次记忆一下,并没有其他的意图。
View工作流程
View工作流程主要指measure、layout、draw这三个流程,即测量、布局和绘制。
- measure确定View的自身的宽高
- layout确定View在父容器放置的位置
- draw将View绘制到屏幕上。
measure:
为了更好理解measure过程,先了解MeasureSpec。MeasureSpec代表一个32位int值,高2位代表SpecMode,低30位代表SpecSize。SpecMode指的测量模式,SpecSize指在某种测量模式下规格大小。
SpecMode有三种:
-
EXACTLY
精确值模式,父容器已经检测出View所需要的精确大小,这时候View的最终大小就是SpecSize所指定的值。它对应代码LayoutParams(控件layout_width属性和layout_height属性)中match_parent和具体数值。
-
AT_MOST
最大值模式,父容器指定了一个可用大小值,只要不超过父容器允许最大尺寸即可。它对应代码LayoutParams(控件layout_width属性和layout_height属性)中wrap_content。
-
UNSPECIFIED
父容器不对View有任何限制,要多大给多大,如ListView。
注意:自定义控件如果不重写onMeasure(),默认只支持EXACTLY模式。若让View支持wrap_content属性,必须重写onMeasure()来指定wrap_content大小。代码如下:
private int mWidth = 500, mHeight = 500;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
int finalWidth = mWidth > widthSpecSize ? mWidth : widthSpecSize;
int finalheight = mHeight > heightSpecSize ? mHeight : heightSpecSize;
//view支持wrap_content
if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(finalWidth, finalheight);
} else if (widthSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(finalWidth, heightSpecSize);
} else if (heightSpecMode == MeasureSpec.AT_MOST) {
setMeasuredDimension(widthSpecSize, finalheight);
}
}
setMeasuredDimension方法会设置View宽/高的测量值
layout:
layout的作用是ViewGroup用来确定子元素的位置,当ViewGroup的位置被确定后,他在onLayout会遍历所有子元素并调用其layout方法。layout方法大致流程:首先通过setFrame设定View四个顶点位置,View四个顶点一旦确定,那么它在父容器中位置也就确定了。
draw:
重写onDraw()方法,并在Canvas对象上绘制所需要的图形,有画笔和画布就可以,这也是学习的难点以及重点。
自定义attrs属性
values目录下创建attrs.xml
<resources>
<!--<declare-styleable>声明自定义属性-->
<declare-styleable name="EmptyView">
<!--<attr>声明具体自定义属性-->
<attr name="empty_text" format="string"/>
<attr name="empty_text_color" format="color"/>
<attr name="empty_image" format="reference"/>
</declare-styleable>
</resources>
其中format的值:
color指颜色、reference指资源ID、dimension指尺寸、;string、integer、boolean指对应的基本数据类型。也可以用“|”来分隔不同的属性。