一.自定义属性
1.在res下的values下面新建attrs.xml
2.在布局中使用,声明命名空间
3.在自定义View构造方法中通过TypedArray获取属性
4.必须回收 array.recycle();
二.重写onMeasure()方法
//widthMeasureSpec : 一个32位的值,会包含两个信息:
//模式:前2位;对应的值:后30位
// 获取宽高的模式
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
// 获取前两位
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
// 获取宽高的值
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
// 获取后面30位
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
MeasureSpec.AT_MOST : 在布局中指定了wrap_content
MeasureSpec.EXACTLY : 在不居中指定了确切的值 100dp match_parent fill_parent
MeasureSpec.UNSPECIFIED : 尽可能的大,很少能用到。ListView , ScrollView 在测量子布局的时候会用UNSPECIFIED 。ScrollView + ListView 会显示不全问题
三.重写onDraw(canvas)
常用方法:
canvas.drawText();//画文本
canvas.drawArc();//画弧
canvas.drawCircle();//画圆
canvas.drawBitmap();
canvas.drawLine();canvas.drawLines();
canvas.drawPath();
canvas.drawRect();canvas.drawRoundRect();
canvas.drawOval();
canvas.drawPoint();
问题:自定义view时继承LinearLayout能不能显示效果?不能,默认的ViewGroup不会调用onDraw方法,为什么?
draw(Canvas canvas)方法中,采用模板设计:
if (!dirtyOpaque) onDraw(canvas);
dispatchDraw(canvas);
onDrawForeground(canvas);
dirtyOpaque是false才执行,其实就是由privateFlags -> mPrivateFlags的值决定
final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE
&& (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
mPrivateFlags 到底是怎么赋值的?在View的构造函数中调用 computeOpaqueFlags
protected void computeOpaqueFlags() {
if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) {
mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND;
} else {
mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND;
}
final int flags = mViewFlags;
if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) ||
(flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY ||
(flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) {
mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS;
} else {
mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS;
}
}
在ViewGroup的initViewGroup方法中:
private void initViewGroup() {
// ViewGroup doesn't draw by default
if (!debugDraw()) {
setFlags(WILL_NOT_DRAW, DRAW_MASK);
}
}
这里会使mPrivateFlags重新赋值,导致dirtyOpaque为true,最终不执行onDraw方法
如何解决? 思路:改变 mPrivateFlags
1.在自定义View构造方法中调用一下方法,二选一即可
(1).setBackgroundColor(Color.TRANSPARENT);
(2).setWillNotDraw(false);
2.调用dispatchDraw()