【記錄】Android關(guān)于WebView內(nèi)容轉(zhuǎn)PDF文件打印及其遇到的問(wèn)題解決方案

需求描述:將WebView渲染出來(lái)的內(nèi)容轉(zhuǎn)化為PDF文件打印

關(guān)于內(nèi)容轉(zhuǎn)為文件打印,google一下,文章還是有很多的,這里簡(jiǎn)單的貼一下

  1. app/build.gradle 添加

implementation "com.linkedin.dexmaker:dexmaker:2.28.1"
implementation "com.linkedin.dexmaker:dexmaker-mockito:2.28.1"

  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)了,其中全部的圖片都加載了。

具體的原理大家自己搜索下,這里就不貼鏈接了

  1. ScrollView高度測(cè)試原理
  2. 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ū)賜教。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 表情是什么,我認(rèn)為表情就是表現(xiàn)出來(lái)的情緒。表情可以傳達(dá)很多信息。高興了當(dāng)然就笑了,難過(guò)就哭了。兩者是相互影響密不可...
    Persistenc_6aea閱讀 129,881評(píng)論 2 7
  • 16宿命:用概率思維提高你的勝算 以前的我是風(fēng)險(xiǎn)厭惡者,不喜歡去冒險(xiǎn),但是人生放棄了冒險(xiǎn),也就放棄了無(wú)數(shù)的可能。 ...
    yichen大刀閱讀 8,158評(píng)論 0 4

友情鏈接更多精彩內(nèi)容