有时候我们需要保存某个View的内容,截图保存,实现类似截图的功能。本文稍作整理,方便查找使用。
1.截取普通View
View组件显示的内容可以通过cache机制保存为bitmap,相关的API包括:
- void setDrawingCacheEnabled(boolean flag)
- Bitmap getDrawingCache(boolean autoScale)
- void buildDrawingCache(boolean autoScale)
- void destroyDrawingCache()
首先通过setDrawingCacheEnable方法把cache开启,然后再调用getDrawingCache方法获取view的cache图片。
buildDrawingCache方法可以不用调用,因为调用getDrawingCache方法时,若果 cache没有建立,系统会自动调用buildDrawingCache方法生成cache。
要调用destoryDrawingCache方法把旧的cache销毁,才能建立新的;或者调用setDrawingCacheEnabled方法设置为false, 系统也会自动把原来的cache销毁。
所以我们可以使用下面的方法(不适用于包含SurfaceView的View组件)获取指定View的cache并保存:
view.setDrawingCacheEnabled(true);
Bitmap bm = view.getDrawingCache();
view().setDrawingCacheEnabled(false);
获取cache一般还有点占用内存,所以用完有必要进行清理,调用destoryDrawingCache方法把旧的cache销毁;或者调用setDrawingCacheEnabled方法设置为false
2.截取DecorView
decorView是window中的最顶层view,可以从window中获取到decorView,然后decorView有个getWindowVisibleDisplayFrame方法可以获取到程序显示的区域,包括标题栏,但不包括状态栏。获取bitmap的cache和前者一样,只是需要计算出标题栏的高度,然后去掉标题栏即可。如下代码截取Activity中除去标题栏的内容:
View view = getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
Bitmap obtainBitmap = view.getDrawingCache();
// 获取状态栏高度
Rect frame = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
int statusBarHeight = frame.top;
// 获取屏幕长和高
int width = getWindowManager().getDefaultDisplay().getWidth();
int height = getWindowManager().getDefaultDisplay().getHeight();
// 截取当前屏幕,去掉标题栏
Bitmap bitmap = Bitmap.createBitmap(obtainBitmap, 0, statusBarHeight, width, height - statusBarHeight);
view.setDrawingCacheEnabled(false);
3.截取带有SurfaceView的窗口
前面两种办法只适用于普通的View,对于SurfaceView,需要通过别的方式实现。
因为SurfaceView的绘制其实是我们自己完成的,绘制的逻辑大概如下所示:
canvas = mHolder.lockCanvas();
if (canvas != null) {
// 把surfaceview的内容绘制到canvas 上
surfaceview.doDraw(canvas);
mHolder.unlockCanvasAndPost(canvas);
}
上面的Canvas其实是绘制到屏幕上,所以如果要保存SurfaceView的内容,可以用这样一个思路实现:
- 需要获取截图时,创建一个bitmap,并根据这个bitmap创建canvas;
- 重写draw方法,或者自定义新的函数,给SurfaceView传入一个Canvas;
- 在SurfaceView里面把传入的Canvas按照都doDraw的逻辑绘制绘制一遍(cache应该也是类似的事情);
- 在SurfaceView外通过返回的Canvas将其保存。
以上思路其实也相当于开发者自己实现getDrawingCache()方法,所以具体实现上有很多方式。
之前被困惑一段时间,因此写了此文。
4.保存位图
下面是一段用于保存位图的代码片段:
/**
* Save bitmap
*
* @param bm Bitmap need to save.
* @param strFileName Save the bitmap into the file name.
*/
private static void savePic(Bitmap bm, String strFileName) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(strFileName);
if (null != fos) {
bm.compress(Bitmap.CompressFormat.PNG, 90, fos);
fos.flush();
fos.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}