Android笔记 自定义View(六):Canvas使用之绘制图片

本章看下Canvas绘制位图相关内容

目录

一、绘制位图(drawBitmap)

二、绘制矢量图(drawPicture)

三、总结 


一、drawBitmap

绘制bitamp方法说明:

/*
* @param
*  bitmap 位图
*  left 绘制区域距离左边界偏移量
*  top 绘制区域距离上边界偏移量
*  paint 画笔
* 在View中指定位置绘制bitmap
* 注:传入的参数中的偏移量是指对于View的偏移。
*/
public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, 
            @Nullable Paint paint)

/*
* @param
*  bitmap 位图
*  src bitmap需要绘制的面积,若src的面积小于bitmap时会对bitmap进行裁剪,
*      一般来说需要绘制整个bitmap时可以为null 
*  dst 在画布中指定绘制bitmap的位置,当这个区域的面积与bitmap要显示的面积不匹配时,
*      会进行缩放,不可为null 
*  paint 画笔
* 在指定位置绘制指定大小的bitmap
*/
public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull RectF dst,
            @Nullable Paint paint)
public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst,
            @Nullable Paint paint)

/*
* @param
*  bitmap 位图
*  matrix 当绘制位图时需要转变时使用的矩阵
*  paint 画笔
* 使用指定的矩阵绘制位图
*/
public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, 
            @Nullable Paint paint)

java代码:

    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setLayerType(LAYER_TYPE_SOFTWARE,null);
        mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.you);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 画出原图像
        canvas.drawBitmap(mBitmap, 0, 0, null);
        // 指定图片绘制区域(左上角的四分之一)
        Rect src = new Rect(0,0,mBitmap.getWidth()/2,mBitmap.getHeight()/2);
        // 指定图片在屏幕上显示的区域(原图大小)
        Rect dst = new Rect(mBitmap.getWidth()+50,0,mBitmap.getWidth()+50+mBitmap.getWidth(),mBitmap.getHeight());
        canvas.drawBitmap(mBitmap, src,dst,null);

    }

效果:

drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)方法是通过矩阵对图片进行一些变换处理。如下:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 画出原图像
        canvas.drawBitmap(mBitmap, 0, 0, null);
        Matrix matrix = new Matrix();
        matrix.postScale(0.5f, 0.5f);
        canvas.drawBitmap(mBitmap, matrix,null);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 画出原图像
        canvas.drawBitmap(mBitmap, 0, 0, null);
        Matrix matrix = new Matrix();
        matrix.postTranslate(100f, 100f);
        canvas.drawBitmap(mBitmap, matrix,null);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 画出原图像
        canvas.drawBitmap(mBitmap, 0, 0, null);
        Matrix matrix = new Matrix();
        matrix.postRotate(90, mBitmap.getWidth()*0.5f,mBitmap.getHeight()*0.5f);
        canvas.drawBitmap(mBitmap, matrix,null);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 画出原图像
        canvas.drawBitmap(mBitmap, 0, 0, null);
        Matrix matrix = new Matrix();
        matrix.postSkew(0.5f,0.5f);
        canvas.drawBitmap(mBitmap, matrix,null);
    }

以上是Matrix的一些简单变换操作。它的原理比较复杂,后面在详细说明。

二、drawPicture

在Canvas中还有一类绘制图片的方法,如下:

/*
* 在绘制图片之前保存Canvas状态,绘制完成之后回复Canvas
*/
public void drawPicture(@NonNull Picture picture)

/*
* 在指定区域内绘制图片,当图片大小不匹配时进行适当的缩放
*/
public void drawPicture(@NonNull Picture picture, @NonNull RectF dst) 
public void drawPicture(@NonNull Picture picture, @NonNull Rect dst)

从上面可以看出关键参数Picture,下面我们来说下Picture类,看下官方文档对其的解释:

A Picture records drawing calls (via the canvas returned by beginRecording) and can then play them back into Canvas (via draw(Canvas) ordrawPicture(Picture)).For most content (e.g. text, lines, rectangles), drawing a sequence from a picture can be faster than the equivalent API calls, since the picture performs its playback without incurring any method-call overhead.

上面的解释没有懂,我直接百度到的解释大概意思是:Picture和录像功能是类似的,只不过Picture录的是Canvas中绘制的内容。我们把Canvas绘制点,线,矩形等诸多操作用Picture录制下来,下次需要的时候拿来就能用,使用Picture相比于再次调用绘图API,开销是比较小的,也就是说对于重复的操作可以更加效率。

PS:可以把Picture看作是一个录制Canvas操作的录像机。下面在看下Picture的相关方法。

相关方法 简介
public int getWidth () 获取宽度
public int getHeight () 获取高度
public Canvas beginRecording (int width, int height) 开始录制 (返回一个Canvas,在Canvas中所有的绘制都会存储在Picture中)
public void endRecording () 结束录制
public void draw (Canvas canvas) 将Picture中内容绘制到Canvas中

上面表格中基本上已经列出了Picture的主要方法,我们主要看下后面三个方法:很明显,beginRecording 和 endRecording 是成对使用的,一个开始录制,一个是结束录制,两者之间的操作将会存储在Picture中。然后通过draw()方法将Picture保存的操作绘制出来。也就是说在自定义View中使用drawPicture()方法要分为两个步骤:

  • 第一步:使用Picture录制内容
    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //注意:关闭硬件加速
        setLayerType(LAYER_TYPE_SOFTWARE,null);
        mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.you);
        mPicture = new Picture();
        recording();
       
    }

    //录制内容
    private void recording() {
        Canvas canvas = mPicture.beginRecording(500, 500);
        canvas.drawBitmap(mBitmap, 0, 0, null);
        mPicture.endRecording();
    }
  • 第二步:将录制的内容显示出来(三种方式)

将Picture录制的内容显示出来有主要有三种方式:

方式 说明
1、mPicture.draw(canvas) 使用Picture提供的draw方法绘制。
2、canvas.drawPicture(mPicture) 使用Canvas提供的drawPicture方法绘制。
3、pictureDrawable.draw(canvas); 将Picture包装成为PictureDrawable,使用PictureDrawable的draw方法绘制。

我们来分别看下使用情况:

1、mPicture.draw(canvas):

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPicture.draw(canvas);
    }

通过官方文档对这个方法的说明,我们发现在21之前的版本使用时会对Canvas的状态有影响(Matrix clip等),而且对绘制结果可控性较弱。具体的影响是什么我也没有搞明白。总之,一般不去使用它,推荐使用后面两种方式。

2、canvas.drawPicture(mPicture):

这种方式Canvas提供三个重载方法,就是我们上面列出的:

public void drawPicture (Picture picture) 
public void drawPicture (Picture picture, Rect dst) 
public void drawPicture (Picture picture, RectF dst)

我们看下效果:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawPicture(mPicture);
        canvas.drawPicture(mPicture,new RectF(0, 0, 300, 300));
    }

发现后面两个重载方法会对图片进行缩放。Rect dst指定图片显示的区域,只不过精度不同。

3、pictureDrawable.draw(canvas):

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    // 包装成为Drawable
    PictureDrawable drawable = new PictureDrawable(mPicture);
    // 设置绘制区域 -- 注意此处所绘制的内容不匹配时,
    // 只会显示一部分,不会对picture进行裁剪
    drawable.setBounds(0,0,200,mPicture.getHeight());
    // 绘制
    drawable.draw(canvas);
}

效果图:

三、总结 

本篇介绍了Canvas绘制图片的相关内容,其中涉及到Matrix没有做深入了解。其实对于图片的复杂操作都是利用Matrix来实现的,后面会单独介绍Matrix相关内容。

祝:工作顺利!

展开阅读全文

没有更多推荐了,返回首页