Android之WebView网页滚动截图

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*/@JavascriptInterfacepublic 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() {@Overridepublic void run() {Bitmap bitmap = CaptureUtil.getWebViewBitmap(activity, body);if (null != bitmap) ImageUtil.save(activity, bitmap, file, 100);}});return path;}@JavascriptInterfacepublic String Capture(String name) {return Capture(name, true);}@JavascriptInterfacepublic 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://www.cnblogs.com/zhouzme/p/5758388.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/418338.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端学习(1998)vue之电商管理系统电商系统之实现步骤条和tab栏的数据

目录结构 router.js import Vue from vue import Router from vue-router import Login from ./components/Login.vue import Home from ./components/Home.vue import Welcome from ./components/Welcome.vue import Users from ./components/user/Users.vue import Right fr…

asp.net core 在Ubuntu 运行

asp.net core 在Ubuntu 运行 环境: Ubuntu 16.04dotnet-dev-1.0.0-preview2-003121Visual Studio 2015 update 3 Ubuntu 安装.net core 参考:https://www.microsoft.com/net/core#ubuntu 1.添加源 sudo sh -c echo "deb [archamd64] https://apt-mo.trafficmanager.net/re…

前端学习(1999)vue之电商管理系统电商系统之分析表单的数据

目录结构 router.js import Vue from vue import Router from vue-router import Login from ./components/Login.vue import Home from ./components/Home.vue import Welcome from ./components/Welcome.vue import Users from ./components/user/Users.vue import Right fr…

docker中的容器和镜像

最近学习了docker&#xff0c;感觉容器和镜像学的有点模糊。 特别是镜像和容器&#xff0c;感觉完全分不开&#xff0c;所以在此学习&#xff0c;然后总结了一下&#xff0c;便于后面的学习。 *************** 补充&#xff1a;经过我的一段时间使用&#xff0c;现在再来说一…

前端学习(2000)vue之电商管理系统电商系统之绘制基本面板的结构

目录结构 router.js import Vue from vue import Router from vue-router import Login from ./components/Login.vue import Home from ./components/Home.vue import Welcome from ./components/Welcome.vue import Users from ./components/user/Users.vue import Right fr…

微服务架构与组件总览

最近在各个地方总是看到微服务、消息队列、Redis、K8s等词语&#xff0c;下面就对他们涉及的概念进行一个总体的介绍&#xff0c;具体的技术实现目前还未完全掌握&#xff0c;那就先从整体把握关系&#xff0c;更方便以后的深入学习。(参考知乎和CSDN资料) 全篇以电商服务千万…

前端学习(2001)vue之电商管理系统电商系统之获取商品分类数据

目录结构 router.js import Vue from vue import Router from vue-router import Login from ./components/Login.vue import Home from ./components/Home.vue import Welcome from ./components/Welcome.vue import Users from ./components/user/Users.vue import Right fr…

shamir门限方案阅读与密码学课程感想

这里重点谈一下对Adi Shamir的关于阈值密钥分 享方案的论文《How to Share a Secret 》的理解&#xff0c;以及这两周密码学课堂的学习感想。 想要看懂一篇论文&#xff0c;首先要知道它是为了解决什么问题&#xff0c;然后看它为了解决这个问题采用了什么样 的方法&#xff0c…

前端学习(2002)vue之电商管理系统电商系统之绘制商品分类的级联选择器

目录结构 router.js import Vue from vue import Router from vue-router import Login from ./components/Login.vue import Home from ./components/Home.vue import Welcome from ./components/Welcome.vue import Users from ./components/user/Users.vue import Right fr…

jdbc建立数据库连接的helloword

package com.guoguo.db; import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException; import com.mysql.jdbc.Connection;import com.mysql.jdbc.Statement; public class DBUtil { //数据库连接地址 private static final String URL "jdb…

前端学习(2003)vue之电商管理系统电商系统之之允许三级选择

目录结构 router.js import Vue from vue import Router from vue-router import Login from ./components/Login.vue import Home from ./components/Home.vue import Welcome from ./components/Welcome.vue import Users from ./components/user/Users.vue import Right fr…

搭建hexo博客并部署到github上

hexo是由Node.js驱动的一款快速、简单且功能强大的博客框架&#xff0c;支持多线程&#xff0c;数百篇文章只需几秒即可生成。支持markdown编写文章&#xff0c;可以方便的生成静态网页托管在github上。 感觉不错。 前端人员都在用github分享自己的代码。所以想着用hexo部署到g…

前端学习(2004)vue之电商管理系统电商系统之阻止页签切换

目录结构 router.js import Vue from vue import Router from vue-router import Login from ./components/Login.vue import Home from ./components/Home.vue import Welcome from ./components/Welcome.vue import Users from ./components/user/Users.vue import Right fr…

前端学习(2005)vue之电商管理系统电商系统之获取动态参数列表

目录结构 router.js import Vue from vue import Router from vue-router import Login from ./components/Login.vue import Home from ./components/Home.vue import Welcome from ./components/Welcome.vue import Users from ./components/user/Users.vue import Right fr…

Mysql存储结构B树与B+树与索引

首先要说明的是&#xff0c;B-树和B树是指同一个结构&#xff0c;并没有所谓的B减树&#xff0c;两种树是B-树和B树。 Mysql存储结构是一个B树。 1.存储结构与索引 众所周知&#xff0c;索引是关系型数据库中给数据库表中一列或多列的值排序后的存储结构&#xff0c;它是一种…

前端学习(2006)vue之电商管理系统电商系统之绘制商品参数的复选框

目录结构 router.js import Vue from vue import Router from vue-router import Login from ./components/Login.vue import Home from ./components/Home.vue import Welcome from ./components/Welcome.vue import Users from ./components/user/Users.vue import Right fr…

酒厂选址(codevs 1507)

题目描述 Description Abstinence&#xff08;戒酒&#xff09;岛的居民们酷爱一种无酒精啤酒。以前这种啤酒都是从波兰进口&#xff0c;但今年居民们想建一个自己的啤酒厂。岛上所有的城市都坐落在海边&#xff0c;并且由一条沿海岸线的环岛高速路连接。酒厂的投资者收集了关于…

前端学习(2007)vue之电商管理系统电商系统之优化复选框的样式

目录结构 router.js import Vue from vue import Router from vue-router import Login from ./components/Login.vue import Home from ./components/Home.vue import Welcome from ./components/Welcome.vue import Users from ./components/user/Users.vue import Right fr…

MapReduce改造fp-growth算法

1. FP-Growth算法弊端 FP-Growth算法是挖掘频繁项集最常用的算法之一&#xff0c;其是基于迭代FP-Tree生成频繁项集的关联规则算法。此算法仅进行两次数据集扫描&#xff0c;递归迭代构建FP-Tree(FP条件树)&#xff0c;当FP-Tree中只有一个单分支时&#xff0c;递归迭代构建结…

《一线架构师实践指南》—— 读后总结

之前总觉得架构是一件很高大上的工作&#xff0c;跟普通的编码设计不太一样。前一段实践&#xff0c;自己也尝试做过架构的工作&#xff0c;可惜经验不足导致架构非常混乱。这里读完这本书&#xff0c;大体上对架构的工作有所了解&#xff0c;也稍微摸清了些门道。 我理解的架构…