本文的讨论是基于手机在没有root情形。 早期版本的Android是没有提供截屏功能的,到4.0时代后才自带了音量Down+电源键截屏的功能。在开发过程中还可以使用adb命令对手机进行截屏
adb shell screencap -p /sdcard/screenshot.pngadb pull /sdcard/screenshot.pngadb shell rm /sdcard/screenshot.png
一般而言,如果需要App集成截图功能,那么在Android中把一个View用图片获取后保存下来可以使用以下方法
public static Bitmap captureView(View view){ view..setDrawingCacheEnabled(true); Bitmap bmp = view..getDrawingCache(); view..setDrawingCacheEnabled(true); return bmp;}
对于屏幕页面截图,眼尖的你一定想到就可以使用以下方法
public static Bitmap captureScreen(Activity activity) { activity.getWindow().getDecorView().setDrawingCacheEnabled(true); Bitmap bmp=getWindow().getDecorView().getDrawingCache(); return bmp;}
so easy! 当然这个方法截图是无法截取时间电量的状态栏信息的。
截取WebView中显示的所有内容,这个功能就不能用以上提到的方式,否则只能截图屏幕大小的图片。
首先看下截图预览
要实现此功能,就需要使用View类的draw方法,把WebView中的元素绘制到Canvas中,再从Canvas中得到Bitmap对象。而要创建Bitmap就必须得知道宽高,那么WebView的高度应该如何获取呢? 查看WebView源码发现一个方法computeVerticalScrollRange方法,此方法就是计算WebView的实际可以滑动的高度。由于此方法是protected的,我们可以继承WebView扩展一个名为CustomWebView的类,于是该类有以下方法。
/** * 獲取到實際內容高度 * @return */@Overridepublic int computeVerticalScrollRange() { int verticalY = super.computeVerticalScrollRange(); Logger.e("verticalY=" + verticalY); return verticalY;}
创建一个CaptureUtils工具类,添加以下方法,获取到Bitmap并把其保存到sdcard中,在CaptureCallback中返回图片地址。
public static void screenshot(WebView view, CaptureCallback captureCallback) { int width = view.getWidth(); if (view instanceof CustomWebView) { int height = ((CustomWebView) view).computeVerticalScrollRange(); view.postDelayed(() -> { Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444); Canvas canvas = new Canvas(bmp); view.draw(canvas); String path = FileUtils.saveBitmapToSDCard(Bitmap.createBitmap(bmp, 0, 0, width, height), new File(view.getContext().getExternalCacheDir(), "screenshot.jpg").toString()); captureCallback.finish(path); }, 500); }}
除了截取WebView长图外,再加上顶部的toolbar(不包括时间电量状态栏)和底部的bottomBar的截图,并且需要在截图中添加水印 这就需要用到一开始提到View的截图方法了,分别截取了这几个图片后,拼接组成一个新的长图。添加水印的方法是先把文本绘制成图片,然后水印图绘制到新的长图中。 于是就有了以下方法
/** * 截图,调用此方法之前,说明view已经显示并绘制完成 * * @param toolbar toolbarView * @param bottomBar 底部bar * @param contentView 内容View * @param watermark 是否添加水印 * @param callback 回调,返回截图地址 */public static void screenshot(@NonNull View toolbar, View bottomBar, View contentView, boolean watermark, CaptureCallback callback) { int width = contentView.getWidth(); int topHeight = toolbar.getHeight(); int bottomH = 0; if (bottomBar != null) { bottomH = bottomBar.getHeight(); } int bottomHeight = bottomH; contentView.postDelayed(() -> { int contentViewHeight = contentView.getHeight(); if (contentView instanceof CustomWebView) { contentViewHeight = ((CustomWebView) contentView).computeVerticalScrollRange(); } int height = topHeight + bottomHeight + contentViewHeight;//截图总高度 Bitmap contentBmp = Bitmap.createBitmap(width, contentViewHeight, Bitmap.Config.ARGB_4444); Canvas contentCanvas = new Canvas(contentBmp); contentView.draw(contentCanvas); toolbar.setDrawingCacheEnabled(true); Bitmap topBmp = toolbar.getDrawingCache(); Bitmap bottomBmp = null; if (bottomBar != null) { bottomBar.setDrawingCacheEnabled(true); bottomBmp = bottomBar.getDrawingCache(); } Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bmp); //開始拼圖 Paint paint = new Paint(); canvas.drawBitmap(topBmp, 0, 0, paint);//画底部toolbar canvas.drawBitmap(contentBmp, 0, topHeight, paint);//画内容 if (bottomBmp != null) { canvas.drawBitmap(bottomBmp, 0, contentViewHeight + topHeight, paint);//画底部bar } if (watermark) {//是否添加水印 drawTextMark(width, height, canvas); } //保存圖片 String path = FileUtils.saveBitmapToSDCard(Bitmap.createBitmap(bmp, 0, 0, width, height), new File(contentView.getContext().getExternalCacheDir(), "screenshot.jpg").toString()); callback.finish(path); toolbar.setDrawingCacheEnabled(false); if (bottomBar != null) { bottomBar.setDrawingCacheEnabled(false); } }, 500);}private static void drawTextMark(int bmpWidth, int bmpHeight, Canvas canvas) { TextPaint textPaint = new TextPaint(); int textSize = 24; textPaint.setTextSize(textSize); textPaint.setColor(Color.parseColor("#999999")); textPaint.setAlpha(257); //水印文本由组织名称,用户名和时间组成 String groupName = "组织名称"; String userName = "@用户名"; String datetime = DateUtils.formatDate(new Date()); float w = Math.max(textPaint.measureText(groupName), Math.max(textPaint.measureText(userName), textPaint.measureText(datetime))); int width = (int) Math.ceil(w); int start = (bmpWidth - width) / 2; int top = 320 + textSize * 2; int count = bmpHeight / top; Bitmap bmp = Bitmap.createBitmap(width, textSize * 4, Bitmap.Config.ARGB_8888); Canvas textCanvas = new Canvas(bmp); textCanvas.drawText(groupName, 0, textSize, textPaint); textCanvas.drawText(userName, 0, textSize * 2, textPaint); textCanvas.drawText(datetime, 0, textSize * 3, textPaint); Bitmap newBmp = rotateBitmap(bmp, -45); for (int i = 0; i < count; ++i) { canvas.drawBitmap(newBmp, start, top * i, null); }}private static Bitmap rotateBitmap(Bitmap origin, float degree) { if (origin == null) { return null; } int width = origin.getWidth(); int height = origin.getHeight(); Matrix matrix = new Matrix(); matrix.setRotate(degree); // 围绕原地进行旋转 Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false); if (newBM.equals(origin)) { return newBM; } origin.recycle(); return newBM;}