以前和IOS同事讨论过怎么截屏的操作,当时也不明白,怎么可能将列表截图呢?毕竟列表可以上下滑动呀!最近有个需求,原生布局的界面,生成一个体检报告,我知道这个界面用H5做是可以生成pdf打印的。但现在是原生开发的,因为打印机可以打印bitmap转的byte数组文件,所以要实现页面布局转成bitmap图片。
当布局文件没有超出屏幕高度时:
private Bitmap getViewBitmap(View v) {
v.clearFocus();
v.setPressed(false);
boolean willNotCache = v.willNotCacheDrawing();
v.setWillNotCacheDrawing(false);
int color = v.getDrawingCacheBackgroundColor();
v.setDrawingCacheBackgroundColor(0);
if (color != 0) {
v.destroyDrawingCache();
}
v.buildDrawingCache();
Bitmap cacheBitmap = v.getDrawingCache();
if (cacheBitmap == null) {
return null;
}
Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
v.destroyDrawingCache();
v.setWillNotCacheDrawing(willNotCache);
v.setDrawingCacheBackgroundColor(color);
return bitmap;
}
当布局超出了屏幕的高度,滑动采用Scrollview处理:
public static Bitmap getBitmapByView(ScrollView scrollView) {
int h = 0;
Bitmap bitmap = null;
for (int i = 0; i < scrollView.getChildCount(); i++) {
h += scrollView.getChildAt(i).getHeight();
}
bitmap = Bitmap.createBitmap(scrollView.getWidth(), h,Bitmap.Config.RGB_565);
final Canvas canvas = new Canvas(bitmap);
scrollView.draw(canvas);
return bitmap;
}
以上两种方法则可以满足layout生成bitmap,然后bitmap可以再生成图片进行保存在本地:
public static void savePhotoToSDCard(Bitmap photoBitmap, String path, String photoName) {
if (checkSDCardAvailable()) {
File dir = new File(path);
if (!dir.exists()) {
dir.mkdirs();
}
File photoFile = new File(path, photoName + ".png");
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(photoFile);
if (photoBitmap != null) {
if (photoBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream)) {
fileOutputStream.flush();
}
}
} catch (FileNotFoundException e) {
photoFile.delete();
e.printStackTrace();
} catch (IOException e) {
photoFile.delete();
e.printStackTrace();
} finally {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//检查是否有SD卡
public static boolean checkSDCardAvailable() {
return android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
}
Activity中使用方法:
// 其中contentLly是布局文件
Bitmap bitmap = getBitmapByView(contentLly);
ImageUtils.savePhotoToSDCard(bitmap, "/sdcard/file", "img");
按照指定的宽高或指定比例,重新设置bitmap方法
//把传进来的bitmap对象转换为宽度为x,长度为y的bitmap对象
public static Bitmap transform(Bitmap b, float x, float y) {
int w = b.getWidth();
int h = b.getHeight();
float sx = (float) x / w;
float sy = (float) y / h;
Matrix matrix = new Matrix();
// 也可以按两者之间最大的比例来设置放大比例,这样不会是图片压缩
// float bigerS = Math.max(sx, sy);
// matrix.postScale(bigerS, bigerS);
// 长和宽放大缩小的比例
matrix.postScale(sx, sy);
Bitmap resizeBmp = Bitmap.createBitmap(b, 0, 0, w, h, matrix, true);
return resizeBmp;
}
对于没有在屏幕上显示的控件同样可以获取bitmap,只是需要先进行layout
// 然后View和其内部的子View都具有了实际大小,也就是完成了布局,相当与添加到了界面上。接着就可以创建位图并在上面绘制了:
private void layoutView(View v) {
DisplayMetrics metric = new DisplayMetrics();
mActivity.getWindowManager().getDefaultDisplay().getMetrics(metric);
int width = metric.widthPixels; // 屏幕宽度(像素)
int height = metric.heightPixels; // 屏幕高度(像素)
// 整个View的大小 参数是左上角 和右下角的坐标
v.layout(0, 0, width, height);
int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
int measuredHeight = View.MeasureSpec.makeMeasureSpec(10000, View.MeasureSpec.AT_MOST);
/** 当然,measure完后,并不会实际改变View的尺寸,需要调用View.layout方法去进行布局。
* 按示例调用layout函数后,View的大小将会变成你想要设置成的大小。
*/
v.measure(measuredWidth, measuredHeight);
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
}
private Bitmap loadBitmapFromView(View v) {
int w = v.getWidth();
int h = v.getHeight();
Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bmp);
c.drawColor(Color.WHITE);
/** 如果不设置canvas画布为白色,则生成透明 */
v.layout(0, 0, w, h);
v.draw(c);
return bmp;
}
使用方法:
// 相当与添加到了界面上
layoutView(contentLly);
// 获取bitmap数据
loadBitmapFromView(contentLly);