View的绘制可以分为下面三个过程:
1、Measure
此处View有基本实现
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
public static int getDefaultSize(int size, int measureSpec) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
caseMeasureSpec.UNSPECIFIED:
result = size;
break;
caseMeasureSpec.AT_MOST:
caseMeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}
UNSPECIDIED 父容器不对view有任何限制,要多大有多大,一般用于系统内部测量。
EXACTLY对应的是LayoutParams的match_parent和具体数值(xxxdp),表示父容器已经检测出view的大小。
AT_MOST对应的是LayoutParams的wrap_content,父容器指定了可用的大小。
2、Layout
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
}
没有子View需要排列,所以这一步其实我们不需要做额外的工作。插一句,对ViewGroup类,onLayout方法中,我们需要将所有子View的大小宽高设置好
3、Draw
protected void onDraw(Canvas canvas) {
}
例:循环调用了ondrow,写着玩的当不得真
protected void onDraw(Canvas canvas) {
super.onDraw(canvas); //get screen width
float sw = this.getMeasuredWidth();
if (startX >= sw + (hSpace + space) - (sw % (hSpace + space))) {
startX = 0;
} else {
startX += delta; }
float start = startX; // draw latter parse
while (start < sw) {
canvas.drawLine(start, 5, start + hSpace, 5, mPaint); start += (hSpace + space);
}
start = startX - space - hSpace; // draw front parse
while (start >= -hSpace) {
canvas.drawLine(start, 5, start + hSpace, 5, mPaint); start -= (hSpace + space);
}
if (index >= 700000) {
index = 0;
}
invalidate();
}
三个重要的方法
requestLayout View重新调用一次layout过程。
invalidate View重新调用一次draw过程
forceLayout 标识View在下一次重绘,需要重新调用layout过程。