一、普通View生成图片的原理
我们先来分析下从普通View中获取图片的方法。代码如下:
public Bitmap getBitmapFromView(View view){
if (view == null) {
return null;
}
view.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);
view.destroyDrawingCache();
return bitmap;
}
上面是从普通view获取图像的方法,核心API是view.getDrawingCache(),跟踪源码可知最终调用到View.java的buildDrawingCacheImpl()方法。我们来研究下这个方法的实现。
frameworks\base\core\java\android\view\View.java
private void buildDrawingCacheImpl() {
Bitmap bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), width, height, quality);
Canvas canvas = new Canvas(bitmap);
final int restoreCount = canvas.save();
if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
dispatchDraw(canvas);
} else {
draw(canvas);
}
canvas.restoreToCount(restoreCount);
}
上面是我精简后的方法,可以很清晰的看到普通View生成图像的原理就是,生成一个新的Bitmap,把这个新的Bitmap设置给一个Canvas,然后再调用源View的Draw方法,将图像原型绘制到新Bitmap上。简单说,就是通过Canvas把源View的图像原型绘制到新Bitmap中,这样再将新Bitmap保存起来就得到了View的图像。
在Android中绘制一个二维图像需要四个基本组件:
1、a Bitmap:保存图像像素数据(to hold the pixels)
2、a Canvas:包含一系列绘制和图像变换的方法(to host the draw calls,writing into the bitmap)
3、a drawing primitive:图像原型 (e.g. Rect, Path, text, Bitmap)
4、a paint:画笔描述绘制颜色、风格 (to describe the colors and styles for the drawing)
一句话描述:canvas 用画笔把图像原型绘制到bitmap上。
二、同理为啥不能从SurfaceView中获取图片呢?
从上分析中可以知道获取普通View的图形就是调用View的Draw方法在新的Bitmap上再绘制一次。那为啥同样的逻辑在SurfaceView上无效呢?让我们来看下SurfaceView的Draw方法的实现。
frameworks\base\core\java\android\view\SurfaceView.java
@Override
public void draw(Canvas canvas) {
if (mWindowType != WindowManager.LayoutParams.TYPE_AP