Android 自定义View总结 —— onDraw

本文介绍Android自定义View的实现原理及Canvas基本用法,包括onDraw方法的作用、View绘制流程、Canvas提供的绘图方法等,并提供了一个具体的圆形绘制示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

说明:本博客为原创,转载请注明出处 优快云-ANDROID笔记栈
由于作者水平有限,错误在所难免,请见谅,可以留言,本人会及时改正


索引


onDraw

自定义View最后显示的内容就是通过重载这个方法来实现的

protected void onDraw(Canvas canvas) {
    // 在View中这个方法留空了,交给实现类去做了
}

在xml中添加如下代码,运行结果还是能看到一个大小48x48(dp)、背景为红色的View,但是我们在自定义View的onDraw中什么都没做,这个红色背景是什么来的呢?

<com.neulion.android.dl.customviewdemo.widget.DLCustomView
    android:layout_width="48dp"
    android:layout_height="48dp"
    android:background="#ff0000" />

View呈现图像的入后是draw方法

public void draw(Canvas canvas) {
    ...
    // Step 1, draw the background, if needed
    int saveCount;

    if (!dirtyOpaque) {
        drawBackground(canvas);
    }

    // skip step 2 & 5 if possible (common case)
    if (!verticalEdges && !horizontalEdges) {
        // Step 3, draw the content
        if (!dirtyOpaque) onDraw(canvas);

        // Step 4, draw the children
        dispatchDraw(canvas);

        // Overlay is part of the content and draws beneath Foreground
        if (mOverlay != null && !mOverlay.isEmpty()) {
            mOverlay.getOverlayView().dispatchDraw(canvas);
        }

        // Step 6, draw decorations (foreground, scrollbars)
        onDrawForeground(canvas);

        // we're done...
        return;
    }
    ...
}

在draw方法中,步骤写的很详细了
1.先画背景 (#2,#5略过,所以在Demo中还是能看到红色背景)
3.绘制自己
4.绘制子View
6.绘制前景

Canvas

知道了View的绘制过程,在onDraw中只要操作canvas就可以实现你想要的结果了

下面看一下ImageView的onDraw方法

protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (mDrawable == null) {
            return; // couldn't resolve the URI
        }

        if (mDrawMatrix == null && mPaddingTop == 0 && mPaddingLeft == 0) {
            mDrawable.draw(canvas);// 在画布上把Drawable画上去了
        } 
        else {
            final int saveCount = canvas.getSaveCount();
            canvas.save();
            ...
            mDrawable.draw(canvas);
            canvas.restoreToCount(saveCount);
        }
    }

在Canvas中定义了许多方法

// 矩形
public void drawRect(...);
// 图片
public void drawBitmap(...)
// 圆
public void drawCircle(...)
// 线
public void drawLine(...)
// ...

Demo

GitHub地址: GitHub
环境: Windows7+JAVA8
IDE: AndroidStdio2.2.2
compileSdkVersion:24
测试设备:Nexus5(6.0.1)

demo中有多个示例,请在Manifest中更改默认启动项

运行结果截图
ViewOnDraw示例

// DLCustomCircleView
// 这里只是简单的示例,Canvas有许多复杂的操作请自行google
protected void onDraw(Canvas canvas){
    // 居中,以中心点开始画圆
    if (mCircleGravity == GRAVITY_CENTER){
        canvas.drawCircle(getWidth() / 2, getHeight() / 2, mCircleRadius, mPaint);
    }
    // 以左上角为原点
    else if (mCircleGravity == GRAVITY_START){
        canvas.drawCircle(0, 0, mCircleRadius, mPaint);
    }
    // 以右下角为原点,
    else if (mCircleGravity == GRAVITY_END){
        canvas.drawCircle(getWidth(), getHeight(), mCircleRadius, mPaint);
    }
}
// 测量View的小大
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
    int width;

    int height;

    int widthMode = MeasureSpec.getMode(widthMeasureSpec);

    // 如果是wrap_content,大小就是圆直径
    if (widthMode != MeasureSpec.EXACTLY){
        width = mCircleRadius * 2;
    }
    else{
        width = MeasureSpec.getSize(widthMeasureSpec);
    }

    int heightMode = MeasureSpec.getMode(heightMeasureSpec);

    if (heightMode != MeasureSpec.EXACTLY){
        height = mCircleRadius * 2;
    }
    else{
        height = MeasureSpec.getSize(heightMeasureSpec);
    }
        setMeasuredDimension(width, height);
}
// 初始化的时候,读取xml属性
private void initialize(Context context, AttributeSet attrs){
    TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.DLCustomCircleView);

    mCircleGravity = array.getInt(R.styleable.DLCustomCircleView_circleGravity, GRAVITY_CENTER);

    int mCircleColor = array.getColor(R.styleable.DLCustomCircleView_circleColor, 0);

    mCircleRadius = array.getInt(R.styleable.DLCustomCircleView_circleRadius, 16);

    array.recycle();

    // 初始化Paint,画笔也有很多属性 自行google
    mPaint = new Paint();

    mPaint.setColor(mCircleColor);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值