Android WebView實(shí)現(xiàn)網(wǎng)頁(yè)滾動(dòng)截圖
WebView 網(wǎng)頁(yè)滾動(dòng)截屏,可對(duì)整個(gè)網(wǎng)頁(yè)進(jìn)行截屏而不是僅當(dāng)前屏幕哦!
注意若Web頁(yè)面存在position:fixed; 的話得在調(diào)用前設(shè)置為 position:absolute; 哦,否則會(huì)出現(xiàn)很多次的,請(qǐng)看下面的具體解說(shuō)吧!!
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(); // 容器內(nèi)容實(shí)際高度 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調(diào)用截屏操作
/** * 屏幕截圖 * @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); }
示例圖:我先通過(guò) JS 觸發(fā)顯示了一個(gè)原生的 Button按鈕, 然后WebView跳轉(zhuǎn)到 csdn 頁(yè)面,然后點(diǎn)擊截屏按鈕用來(lái)觸發(fā)網(wǎng)頁(yè)截屏的。下面的圖是我手動(dòng)截的圖,不是上面代碼的效果哈,下下面很長(zhǎng)的那張才是Java程序的網(wǎng)頁(yè)截圖。
測(cè)試CSDN的網(wǎng)頁(yè)完整截圖:比較長(zhǎng)哦~ 一般截圖的功能都用于特殊的頁(yè)面,如活動(dòng)頁(yè)面之類的,不會(huì)太長(zhǎng),那樣是沒(méi)有問(wèn)題的。若是這種滾動(dòng)到底部自動(dòng)加載的話可能就會(huì)很長(zhǎng)很長(zhǎng)很長(zhǎng)啦·····,自己看著辦吧。。
但這里有個(gè)BUG,頂部固定Banner條每次截屏都有,這個(gè)有解決辦法,不過(guò)得是你自己的網(wǎng)頁(yè)才有操作權(quán)限哦,需要修改JS啦。
當(dāng)截圖JS命令觸發(fā)前,把頂部懸浮的樣式設(shè)置為絕對(duì)定位,當(dāng)截屏完成后再改回固定定位即可,沒(méi)什么難度了。
截屏是需要一些時(shí)間的,所以需要預(yù)設(shè)一個(gè)定時(shí)器來(lái)操作,JS栗子如下:
JS.Capture 是 WebView 綁定的自定義 Javascript 類對(duì)象
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);
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android WebView打開網(wǎng)頁(yè)一片空白的解決方法
- Android開發(fā)筆記之如何正確獲取WebView的網(wǎng)頁(yè)Title
- 詳解android 用webview加載網(wǎng)頁(yè)(https和http)
- Android開發(fā)中使用WebView控件瀏覽網(wǎng)頁(yè)的方法詳解
- Android編程實(shí)現(xiàn)webview將網(wǎng)頁(yè)打包成apk的方法
- Android中替換WebView加載網(wǎng)頁(yè)失敗時(shí)的頁(yè)面
- Android中Webview打開網(wǎng)頁(yè)的同時(shí)發(fā)送HTTP頭信息方法
- Android webView如何輸出自定義網(wǎng)頁(yè)
相關(guān)文章
Android仿天天動(dòng)聽歌曲自動(dòng)滾動(dòng)view
這篇文章主要為大家詳細(xì)介紹了Android仿天天動(dòng)聽歌曲自動(dòng)滾動(dòng)view的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-05-05Android模擬器接收UDP數(shù)據(jù)包的若干問(wèn)題分析
這篇文章主要介紹了Android模擬器接收UDP數(shù)據(jù)包的若干問(wèn)題,結(jié)合實(shí)例形式較為詳細(xì)的分析了Android模擬器接收UDP數(shù)據(jù)的使用方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下2016-04-04Android為TextView添加字體庫(kù)和設(shè)置描邊的方法
本篇文章主要介紹了Android為TextView添加字體庫(kù)和設(shè)置描邊的方法,具有一定的參考價(jià)值,有興趣的可以了解一下2017-09-09Eclipse打開時(shí)“發(fā)現(xiàn)了以元素''d:skin''”開頭的無(wú)效內(nèi)容。此處不應(yīng)含有子元素的解決方法
這篇文章主要介紹了Eclipse打開時(shí)“發(fā)現(xiàn)了以元素'd:skin'”開頭的無(wú)效內(nèi)容。此處不應(yīng)含有子元素的解決方法,涉及Android sdk中devices.xml文件的修改,需要的朋友可以參考下2016-01-01Android獲取手機(jī)位置的實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了Android獲取手機(jī)位置的實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-11-11Android編程布局(Layout)之AbsoluteLayout用法實(shí)例分析
這篇文章主要介紹了Android編程布局(Layout)之AbsoluteLayout用法,結(jié)合實(shí)例形式簡(jiǎn)單分析了Android絕對(duì)布局AbsoluteLayout的實(shí)現(xiàn)方法,需要的朋友可以參考下2015-12-12Android scheme 跳轉(zhuǎn)的設(shè)計(jì)與實(shí)現(xiàn)詳解
這篇文章主要介紹了Android scheme 跳轉(zhuǎn)的設(shè)計(jì)與實(shí)現(xiàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06Android N 7.0中報(bào)錯(cuò):android.os.FileUriExposedException的解決方法
這篇文章主要給大家介紹了關(guān)于在Android N 7.0中報(bào)錯(cuò):android.os.FileUriExposedException的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧2018-05-05