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相关内容。

祝:工作顺利!

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值