我们在自定义控件时,有时都需要重写,这三个函数,那这三个函数到底的作用是什么呢?
测量——onMeasure():决定View的大小
布局——onLayout():决定View在ViewGroup中的位置
绘制——onDraw():如何绘制这个View。
View视图可以是单一的一个如TextView,也可以是一个视图组(ViewGroup)如LinearLayout。
如图:对于多View的视图他的结构是树形结构,最顶层是ViewGroup,ViewGroup下可能有多个ViewGroup或View。
这个树的概念很重要,因为无论我们是在测量大小或是调整布局的时候都是从树的顶端开始一层一层,一个分支一个分支的进行(树形递归)。measure的作用就是为整个View树计算实际的大小,而通过刚才对View树的介绍知道,想计算整个View树的大小,就需要递归的去计算每一个子视图的大小(onLayout,onDraw同理)。还有就是,在测量之前首先要明确一点,需要测量的是一个View(例如TextView),还是一个ViewGroup(例如LinearLayout),还是多个ViewGroup嵌套。如果只有一个View的话我们就测量这一个就可以了,如果有多个View或者ViewGroup嵌套我们就需要循环遍历视图中所有的View(但这些源码已经替我们完成了(更深的了解,可以自己去看源码,代码简单很好理解的),即使在这种情况下:onMeasure(onDraw,onLayout)也只会执行一次)。特别注意一点,有些朋友调试时,会问为什么onMeasure(onDraw,onLayout)会执行多次,有以下可能性:
你调用了addView等函数,因为你看源码会发现,它们最终会调用:invalidate()函数,说白了,就是重绘这个控件。
下面可以通过代码加深对这几个函数的理解:
public class CustomeTextview extends TextView{
public CustomeTextview(Context context, AttributeSet attrs) {
super(context, attrs);
}//控件的尺寸获取
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//该控件的实际宽度
int width=MeasureSpec.getSize(widthMeasureSpec);
System.out.println("====width====="+width);
//获取的这个宽度,对应的精度模式:精确的(EXACTLY)
int widthMode=MeasureSpec.getMode(widthMeasureSpec);
/**
* 如果宽或者高的测量模式非精确值
*/
if (widthMode != MeasureSpec.EXACTLY) {
// getSuggestedMinimumWidth :返回该view能使用的最小高度
width = getSuggestedMinimumWidth();
System.out.println("====minWidth====="+width);
}
}
//控件的位置获取
/**
* 当这个view和其子view被分配一个大小和位置时,被layout调用。
* @param changed 当前View的大小和位置改变了
* @param left 左部位置(相对于父视图)
* @param top 顶部位置(相对于父视图)
* @param right 右部位置(相对于父视图)
* @param bottom 底部位置(相对于父视图)
*/
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
System.out.println("====left====="+left);
System.out.println("====top====="+top);
System.out.println("====right====="+right);
System.out.println("====bottom====="+bottom);
}
//如何绘制这个view
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}}