需求描述:將WebView渲染出來(lái)的內(nèi)容轉(zhuǎn)化為PDF文件打印
關(guān)于內(nèi)容轉(zhuǎn)為文件打印,google一下,文章還是有很多的,這里簡(jiǎn)單的貼一下
- app/build.gradle 添加
implementation "com.linkedin.dexmaker:dexmaker:2.28.1"
implementation "com.linkedin.dexmaker:dexmaker-mockito:2.28.1"
- 實(shí)現(xiàn)類
public class H52PdfTask {
ParcelFileDescriptor descriptor;
PageRange[] ranges;
PrintDocumentAdapter printAdapter;
public void webViewToPdf (WebView webView, String pdfFilePath) {
try {
File pdfFile = new File(pdfFilePath);
if (pdfFile.exists()) {
pdfFile.delete();
}
pdfFile.createNewFile();
descriptor = ParcelFileDescriptor.open(pdfFile, ParcelFileDescriptor.MODE_READ_WRITE);
// 設(shè)置打印參數(shù)
PrintAttributes.MediaSize isoA4 = PrintAttributes.MediaSize.ISO_A4;
PrintAttributes attributes = new PrintAttributes.Builder()
.setMediaSize(isoA4)
.setResolution(new PrintAttributes.Resolution("id", Context.PRINT_SERVICE, 240, 240))
.setColorMode(PrintAttributes.COLOR_MODE_COLOR)
.setMinMargins(PrintAttributes.Margins.NO_MARGINS)
.build();
// 計(jì)算webview打印需要的頁(yè)數(shù)
int numberOfPages = ((webView.getContentHeight() * 240 / (isoA4.getHeightMils())) );
ranges = new PageRange[]{new PageRange(0, numberOfPages)};
// 創(chuàng)建pdf文件緩存目錄
// 獲取需要打印的webview適配器
printAdapter = webView.createPrintDocumentAdapter();
// 開(kāi)始打印
printAdapter.onStart();
printAdapter.onLayout(attributes, attributes, new CancellationSignal(),
getLayoutResultCallback((proxy, method, args) -> {
if (method.getName().equals("onLayoutFinished")) {
L.i("H52PdfTask onLayoutFinished thread=" + Thread.currentThread().getName());
// 監(jiān)聽(tīng)到內(nèi)部調(diào)用了onLayoutFinished()方法,即打印成功
onLayoutSuccess();
} else {
// 監(jiān)聽(tīng)到打印失敗或者取消了打印
L.i("H52PdfTask onLayout fail");
}
return null;
}), new Bundle());
} catch (Exception e) {
e.printStackTrace();
}
}
private void onLayoutSuccess () throws IOException {
PrintDocumentAdapter.WriteResultCallback callback = getWriteResultCallback(new InvocationHandler() {
@Override
public Object invoke (Object o, Method method, Object[] objects) {
if (method.getName().equals("onWriteFinished")) {
L.i("H52PdfTask onLayoutSuccess onWriteFinished thread=" + Thread.currentThread().getName());
} else {
L.i("H52PdfTask onLayoutSuccess fail");
}
return null;
}
});
printAdapter.onWrite(ranges, descriptor, new CancellationSignal(), callback);
}
public static PrintDocumentAdapter.LayoutResultCallback getLayoutResultCallback (InvocationHandler invocationHandler) throws IOException {
return ProxyBuilder.forClass(PrintDocumentAdapter.LayoutResultCallback.class)
.handler(invocationHandler)
.build();
}
public static PrintDocumentAdapter.WriteResultCallback getWriteResultCallback (InvocationHandler invocationHandler) throws IOException {
return ProxyBuilder.forClass(PrintDocumentAdapter.WriteResultCallback.class)
.handler(invocationHandler)
.build();
}
}
?。?!遇到的問(wèn)題
大家都知道,WebView加載Url時(shí),其中的圖片是以懶加載的方式即可見(jiàn)加載,問(wèn)題也就隨之出來(lái)了,當(dāng)我們沒(méi)有瀏覽完整個(gè)網(wǎng)頁(yè)時(shí),打印出來(lái)的文檔,沒(méi)有加載完成的圖片并不能顯示出來(lái),可能是個(gè)菊花,可能是個(gè)灰底的未加載的圖。
怎么才能讓W(xué)ebView一次性將整個(gè)網(wǎng)頁(yè)的圖片全部加載出來(lái)呢,搜索了國(guó)內(nèi)外的文章,發(fā)現(xiàn)更多的都是阻塞圖片加載讓網(wǎng)頁(yè)更快速的顯示出來(lái),并沒(méi)有這種反人類需求的解答(也可能是我的搜索引擎不強(qiáng)),又去看官網(wǎng)WebView相關(guān)的api,也沒(méi)有收獲(也可能是我英文閱讀能力不強(qiáng))。
就在一籌莫展之際,發(fā)現(xiàn)WebView可以被解析成長(zhǎng)截屏( webView.capturePicture()),寫(xiě)個(gè)demo試下(WebView加載完成之后,點(diǎn)個(gè)Button,把生成的長(zhǎng)截屏解析成bitmap設(shè)置到ImageView上),先改個(gè)布局
<ScrollView>
<androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.AppCompatButton .../>
<androidx.appcompat.widget.AppCompatImageView .../>
<WebView ... />
<androidx.appcompat.widget.LinearLayoutCompat>
</ScrollView>
跑完demo測(cè)試發(fā)現(xiàn),長(zhǎng)截屏的方式真的可以,而且更神奇的是,WebView不可見(jiàn)時(shí)(并沒(méi)有上滑WebView使圖片加載)的圖片竟然也在長(zhǎng)截屏上正常的顯示出來(lái)了,這.......這些不可見(jiàn)時(shí)的圖片,是t(愛(ài))m(你)什么時(shí)候被加載的,合著調(diào)了個(gè)截屏的方法就加載了??????
說(shuō)是遲那時(shí)快,忽然提壺灌頂,改了下布局
<ScrollView>
<androidx.appcompat.widget.LinearLayoutCompat>
<WebView ... />
<androidx.appcompat.widget.LinearLayoutCompat>
</ScrollView>
run,我艸,成了,沒(méi)問(wèn)題了,可以了,好起來(lái)了,其中全部的圖片都加載了。
具體的原理大家自己搜索下,這里就不貼鏈接了
- ScrollView高度測(cè)試原理
- WebView高度計(jì)算
關(guān)于ScrollView嵌套WebView的滑動(dòng)沖突問(wèn)題,那才值幾個(gè)錢(qián),呼呼就解決。
注:
ScrollView單嵌套WebView并沒(méi)有發(fā)現(xiàn)沖突(測(cè)試機(jī)型:華為,紅米,小米),可能是我加載的網(wǎng)頁(yè)比較簡(jiǎn)單。
其實(shí)還有其他實(shí)現(xiàn)思路,還沒(méi)來(lái)得及嘗試就解決了,你說(shuō)氣不氣
- 2個(gè)WebView,前臺(tái)WebView加載與用戶交互,后臺(tái)WebView自動(dòng)緩慢滑動(dòng)至底部,對(duì)于打印的操作直接操作后臺(tái)的WebView就好了,不滑動(dòng)到底部不允許打?。。?!
- 1個(gè)WebView,不滑動(dòng)到底部不允許打?。。?!
Ending
如果各位大佬有更好的方法,還請(qǐng)?jiān)u論區(qū)賜教。