构造方法
public CustomView(Context context) {
super(context);
}
public CustomView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
onMeasure() 测量View大小
测量模式一共有三种
模式 | 描述 |
---|---|
MeasureSpec.UNSPECIFIED | 未指定尺寸,父控件没有给子view任何限制,子View可以设置为任意大小。 |
MeasureSpec.EXACTLY | 精确尺寸,表示父控件已经确切的指定了子View的大小。 |
MeasureSpec.AT_MOST | 最大尺寸,表示子View具体大小没有尺寸限制,但是存在上限,上限一般为父View大小。 |
因此,在重写onMeasure方法时要根据模式不同进行尺寸计算,用的比较多的方法:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// setMeasuredDimension这个方法,这个方法决定了当前View的大小
setMeasuredDimension(getMeasuredLength(widthMeasureSpec, true), getMeasuredLength(heightMeasureSpec, false));
}
private int getMeasuredLength(int length, boolean isWidth) {
int specMode = MeasureSpec.getMode(length);
int specSize = MeasureSpec.getSize(length);
int size;
int padding = isWidth ? getPaddingLeft() + getPaddingRight()
: getPaddingTop() + getPaddingBottom();
if (specMode == MeasureSpec.EXACTLY) {
size = specSize;
} else {
size = isWidth ? padding + mWave.length / 4 : DEFAULT_HEIGHT
+ padding;
if (specMode == MeasureSpec.AT_MOST) {
size = Math.min(size, specSize);
}
}
return size;
}
还有一些常用的,如
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
int height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
int widthsize = MeasureSpec.getSize(widthMeasureSpec); //取出宽度的确切数值
int widthmode = MeasureSpec.getMode(widthMeasureSpec); //取出宽度的测量模式
int heightsize = MeasureSpec.getSize(heightMeasureSpec); //取出高度的确切数值
int heightmode = MeasureSpec.getMode(heightMeasureSpec); //取出高度的测量模式
//对View的宽高进行修改了,不要调用 super.onMeasure( widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension( widthsize, heightsize);
}
onSizeChange
视图大小发生改变时调用。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.i("235","onMeasure");
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Log.i("235","onSizeChanged");
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Log.i("235","onLayout");
super.onLayout(changed, left, top, right, bottom);
}
@Override
protected void onDraw(Canvas canvas) {
Log.i("235","onDraw");
}
依次执行顺序:
08-08 12:10:34.066 21861-21861/com.mytest.myapplication I/235: onMeasure
08-08 12:10:34.081 21861-21861/com.mytest.myapplication I/235: onSizeChanged
08-08 12:10:34.081 21861-21861/com.mytest.myapplication I/235: onLayout
08-08 12:10:34.143 21861-21861/com.mytest.myapplication I/235: onMeasure
08-08 12:10:34.143 21861-21861/com.mytest.myapplication I/235: onLayout
08-08 12:10:34.145 21861-21861/com.mytest.myapplication I/235: onDraw
onMeasure方法:作用是计算各控件的大小。系统在渲染页面时会调用各view的onMeasure方法,各控件的onMeasure方法执行顺序是从内到外,即先调用子控件的onMeasure方法,在执行父布局的onMeasure方法。
onLayout方法:根据获取到的尺寸信息渲染这个view。onMeasure方法执行完后会回调onLayout方法。onSizeChanged方法执行完也会回调onLayout方法。执行顺序也是从内到外,即先调用子控件的onLayout方法,在执行父布局的onLayout方法。
关于Activity初始化时的三次measure,两次layout但只一次draw,可以了解下。
onLayout
确定布局的函数,它用于确定子View的位置,在自定义ViewGroup中会用到,他调用的是子View的layout函数。
onDraw
绘制View的函数,包括canvas、paint、path等的用法。
Activity 重新启动页面的时候(如home键退出应用),和Activity 执行生命周期的方法的顺序:
08-08 14:16:29.256 3226-3226/com.mytest.myapplication I/235: onPause
08-08 14:16:32.653 3226-3226/com.mytest.myapplication I/235: onRestart
08-08 14:16:32.654 3226-3226/com.mytest.myapplication I/235: onStart
08-08 14:16:32.654 3226-3226/com.mytest.myapplication I/235: onResume
08-08 14:16:32.687 3226-3226/com.mytest.myapplication I/235: onDraw
在执行完onResume方法之后执行onDraw,另外,调用 invalidata 方法,也会重新执行onDraw,具体为(图片来自大神GcsSloop):
仅为学习笔记,以供翻阅。