本章看下Canvas绘制位图相关内容
目录
一、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相关内容。
祝:工作顺利!