WebView 网页滚动截屏,可对整个网页进行截屏而不是仅当前屏幕哦!
注意若Web页面存在position:fixed; 的话得在调用前设置为 position:absolute; 哦,否则会出现很多次的,请看下面的具体解说吧!!
private static Bitmap getViewBitmapWithoutBottom(View v) { if (null == v) { return null; } v.setDrawingCacheEnabled(true); v.buildDrawingCache(); if (Build.VERSION.SDK_INT >= 11) { v.measure(View.MeasureSpec.makeMeasureSpec(v.getWidth(), View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(v.getHeight(), View.MeasureSpec.EXACTLY)); v.layout((int) v.getX(), (int) v.getY(), (int) v.getX() + v.getMeasuredWidth(), (int) v.getY() + v.getMeasuredHeight()); } else { v.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight()); } Bitmap bp = Bitmap.createBitmap(v.getDrawingCache(), 0, 0, v.getMeasuredWidth(), v.getMeasuredHeight() - v.getPaddingBottom()); v.setDrawingCacheEnabled(false); v.destroyDrawingCache(); return bp; } public static Bitmap getViewBitmap(View v) { if (null == v) { return null; } v.setDrawingCacheEnabled(true); v.buildDrawingCache(); if (Build.VERSION.SDK_INT >= 11) { v.measure(View.MeasureSpec.makeMeasureSpec(v.getWidth(), View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(v.getHeight(), View.MeasureSpec.EXACTLY)); v.layout((int) v.getX(), (int) v.getY(), (int) v.getX() + v.getMeasuredWidth(), (int) v.getY() + v.getMeasuredHeight()); } else { v.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight()); } Bitmap b = Bitmap.createBitmap(v.getDrawingCache(), 0, 0, v.getMeasuredWidth(), v.getMeasuredHeight()); v.setDrawingCacheEnabled(false); v.destroyDrawingCache(); return b; } /** * 获取 WebView 视图截图 * @param context * @param view * @return */ public static Bitmap getWebViewBitmap(Context context, WebView view) { if (null == view) return null; view.scrollTo(0, 0); view.buildDrawingCache(true); view.setDrawingCacheEnabled(true); view.setVerticalScrollBarEnabled(false); Bitmap b = getViewBitmapWithoutBottom(view); // 可见高度 int vh = view.getHeight(); // 容器内容实际高度 int th = (int)(view.getContentHeight()*view.getScale()); Bitmap temp = null; if (th > vh) { int w = getScreenWidth(context); int absVh = vh - view.getPaddingTop() - view.getPaddingBottom(); do { int restHeight = th - vh; if (restHeight <= absVh) { view.scrollBy(0, restHeight); vh += restHeight; temp = getViewBitmap(view); } else { view.scrollBy(0, absVh); vh += absVh; temp = getViewBitmapWithoutBottom(view); } b = mergeBitmap(vh, w, temp, 0, view.getScrollY(), b, 0, 0); } while (vh < th); } // 回滚到顶部 view.scrollTo(0, 0); view.setVerticalScrollBarEnabled(true); view.setDrawingCacheEnabled(false); view.destroyDrawingCache(); return b; } /** * 拼接图片 * @param newImageH * @param newImageW * @param background * @param backX * @param backY * @param foreground * @param foreX * @param foreY * @return */ private static Bitmap mergeBitmap(int newImageH, int newImageW, Bitmap background, float backX, float backY, Bitmap foreground, float foreX, float foreY) { if (null == background || null == foreground) { return null; } Bitmap bitmap = Bitmap.createBitmap(newImageW, newImageH, Bitmap.Config.RGB_565); Canvas cv = new Canvas(bitmap); cv.drawBitmap(background, backX, backY, null); cv.drawBitmap(foreground, foreX, foreY, null); cv.save(Canvas.ALL_SAVE_FLAG); cv.restore(); return bitmap; } /** * get the width of screen */ public static int getScreenWidth(Context ctx) { int w = 0; if (Build.VERSION.SDK_INT > 13) { Point p = new Point(); ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getSize(p); w = p.x; } else { w = ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth(); } return w; } /** * 保存图片 * @param context * @param bitmap * @param file * @param quality * @return */ public static boolean save(Context context, Bitmap bitmap, File file, int quality) { if (bitmap == null) return false; // 获得后缀格式 String abs = file.getAbsolutePath(); String suffix = abs.substring(abs.lastIndexOf(".")+1).toLowerCase(); Bitmap.CompressFormat format; if ("jpg".equals(suffix) || "jpeg".equals(suffix)) { format = Bitmap.CompressFormat.JPEG; } else { format = Bitmap.CompressFormat.PNG; quality = 100; } if (file.exists() && ! file.delete()) return false; try { FileOutputStream stream = new FileOutputStream(file); bitmap.compress(format, quality, stream); stream.flush(); stream.close(); context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file))); return true; } catch (Exception e) { return false; } }
JS调用截屏操作
/** * 屏幕截图 * @param name * @param isRecover */ @JavascriptInterface public String Capture(String name, boolean isRecover) { File dir = new File(Config.PUBLIC_PICTURES_PATH); LogUtil.i("capture", dir.getAbsolutePath()); if (! dir.exists() && ! dir.mkdirs()) return null; final File file = new File(dir, name); String path = file.getAbsolutePath(); if (file.exists() && ! isRecover) return path; body.post(new Runnable() { @Override public void run() { Bitmap bitmap = CaptureUtil.getWebViewBitmap(activity, body); if (null != bitmap) ImageUtil.save(activity, bitmap, file, 100); } }); return path; } @JavascriptInterface public String Capture(String name) { return Capture(name, true); } @JavascriptInterface public String Capture() { String name = String.valueOf(System.currentTimeMillis()) + ".png"; return Capture(name); }
示例图:我先通过 JS 触发显示了一个原生的 Button按钮, 然后WebView跳转到 csdn 页面,然后点击截屏按钮用来触发网页截屏的。下面的图是我手动截的图,不是上面代码的效果哈,下下面很长的那张才是Java程序的网页截图。
测试CSDN的网页完整截图:比较长哦~ 一般截图的功能都用于特殊的页面,如活动页面之类的,不会太长,那样是没有问题的。若是这种滚动到底部自动加载的话可能就会很长很长很长啦·····,自己看着办吧。。
但这里有个BUG,顶部固定Banner条每次截屏都有,这个有解决办法,不过得是你自己的网页才有操作权限哦,需要修改JS啦。
当截图JS命令触发前,把顶部悬浮的样式设置为绝对定位,当截屏完成后再改回固定定位即可,没什么难度了。
截屏是需要一些时间的,所以需要预设一个定时器来操作,JS栗子如下:
JS.Capture 是 WebView 绑定的自定义 Javascript 类对象
var file = ''; var $header = $("#layout-header"); $header.css({ position: "absolute" }); setTimeout(function(){ if (typeof name == "function" || typeof name == "undefined") { file = JS.Capture(); } else { file = JS.Capture(name, isRecover); } }, 500); setTimeout(function(){ JS.Toast("截图已保存", "fast"); JS.Toast(file.replace("storage/emulated/0/", "")); $header.css({ position: "fixed" }); if ($.isFunction(callback)) { callback(file); } }, 1500);