Android WebView实现网页滚动截图

作者:神神的蜗牛 时间:2022-12-12 12:13:03 

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程序的网页截图。

Android WebView实现网页滚动截图

测试CSDN的网页完整截图:比较长哦~ 一般截图的功能都用于特殊的页面,如活动页面之类的,不会太长,那样是没有问题的。若是这种滚动到底部自动加载的话可能就会很长很长很长啦·····,自己看着办吧。。

Android WebView实现网页滚动截图

但这里有个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);

来源:https://blog.csdn.net/zhouzme/article/details/51804824

标签:Android,截图
0
投稿

猜你喜欢

  • Java面向接口编程之命令模式实例详解

    2021-10-19 14:26:53
  • Java Scanner 类的使用小结

    2023-11-29 00:50:39
  • Jmeter如何添加循环控制器

    2021-06-26 20:09:52
  • java批量修改文件后缀名方法总结

    2022-03-15 15:46:04
  • Java生成10个1000以内的随机数并用消息框显示数组内容然后求和输出

    2023-09-30 21:20:19
  • SpringBoot整合Kafka工具类的详细代码

    2022-07-03 14:12:13
  • 掌握Android Handler消息机制核心代码

    2023-11-29 18:29:23
  • Java解析使用JSON的多种方法

    2022-08-13 00:18:01
  • C#读取静态类常量属性和值的实例讲解

    2022-04-15 16:37:34
  • 浅析C++中的函数与指针

    2022-03-13 11:04:28
  • C++类的返回值是*this的成员函数问题

    2023-02-01 19:52:50
  • Spring Security 控制授权的方法

    2023-08-06 19:21:08
  • mybatis-plus的批量新增/批量更新以及问题

    2022-10-28 04:44:16
  • Java守护线程实例详解_动力节点Java学院整理

    2023-03-29 08:14:30
  • JAVA利用HttpClient进行HTTPS接口调用的方法

    2023-10-24 16:28:11
  • C#图像边缘检测(Roberts)的方法

    2022-12-26 15:11:18
  • java并发编程之深入理解Synchronized的使用

    2023-10-11 09:21:13
  • Android Socket实现多个客户端聊天布局

    2022-10-09 08:31:19
  • Java数组(Array)最全汇总(上篇)

    2022-12-19 23:22:30
  • Spring @Bean注解的使用场景与案例实现

    2023-11-20 04:44:22
  • asp之家 软件编程 m.aspxhome.com