Android自定义View基本步骤

一.自定义属性

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()

你可能感兴趣的:(Android自定义View,android)