本篇文章总结Android 自定义View中的一些面试问题。
-
每次自定义view都会有三个构造函数,那么三个构造函数有什么区别呢?分别在什么时候调用?
- 一个构造函数:是在代码里面new View的时候调用,传入context
- 两个构造函数:是在XML中创建View的时候通过反射调用两个参数构造函数
- 三个构造函数:不同主题,需要实现该构造方法
- 自定义View和自定义ViewGroup的区别
- 自定义View主要实现onMeasure+onDraw
- 自定义ViewGroup主要实现onMeasure+onLayout
- MeasureSpec是什么?
MeasureSpec是View中的内部类,基本都是二进制运算,由于int是32位的,用高两位表示mode,低30位表示size,MODE_SHIFT=30 的作用是移位,
- UNSPECIFIED:不对View的大小做限制
- EXACTLY:确切的大小,如:100dp
- AT_MOST:子布局最多只能是specSize中指定的大小,开发人员应该尽可能小得去设置这个布局,并且保证不会超过specSize。系统默认会按照这个规则来设置子布局的大小,开发人员当然也可以按照自己的意愿设置成任意的大小。
- onLayout的时候 view.getWidth()有时会为零是为什么?getWidth()和getMeasuredWidth有什么区别?
- getWidth在layout()过程结束后才能获取到,通过视图右边坐标-左边坐标计算出来的
- getMeasuredWidth 在measure()过程结束后就能获取到,通过setMeasuredDimension()方法来进行设置的。
- 假如我要在View中动态地注册与解除广播接收器,应该在哪里完成呢?
比如,当Window显示时,注册一个监听器,根据监听到的广播事件改变自己的绘制,当Window不可见时,解除注册,因为此时改变自己的绘制已经没有意义了,自己也要跟着Window变成不可见了。
在onAttachedToWindow和onDetachedFromWindow中完成这一功能。代码如下:
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (!mAttached) {
mAttached = true;
IntentFilter filter = new IntentFilter();
//这里确定我们要监听的三种系统广播
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
getContext().registerReceiver(mIntentReceiver, filter);
}
mCalendar = new Time();
onTimeChanged();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mAttached) {
getContext().unregisterReceiver(mIntentReceiver);
mAttached = false;
}
}
- invalidate()、postInvalidate()、requestLayout()
- invalidate方法会执行draw过程,重绘View树,更新界面显示,就可以直接调用invalidate方法。
- postInvalidate() 在子线程中被调用,刷新UI。
- 当View的宽高,发生了变化,不再适合现在的区域,调用requestLayout方法重新对View布局。当View执行requestLayout方法,会向上递归到顶级父View中,再执行这个顶级父View的requestLayout,所以其他View的onMeasure,onLayout也可能会被调用。