【问题标题】:Draw WebView into a Canvas in Android-L在 Android-L 中将 WebView 绘制到 Canvas 中
【发布时间】:2015-05-13 18:55:34
【问题描述】:

我正在使用 Android Print Framework 将 WebView 的 HTML 内容保存为 PDF。由于 Android-L 中的 WebView 有一种新的方法来呈现 WebView 内容,因此建议在创建任何 webview 之前调用 enableSlowWholeDocumentDraw() 方法。这将禁用渲染优化,因此 WebView 将能够渲染整个 HTML 页面。

这是将 WebView 绘制成 Canvas 的部分代码。

PdfDocument.Page page = document.startPage(pageInfo);
mWebView.draw(page.getCanvas());

我尝试从 Application、BaseActivity 以及在我的 Fragment 中创建 WebView 之后和之前调用 WebView.enableSlowWholeDocumentDraw()。但这没有帮助。

我尝试通过将层类型设置为软件和硬件来启用/禁用硬件加速,但这也没有帮助。我仍然无法绘制整个 WebView。只有可见部分会被绘制到画布上。

有人注意到这种行为吗?是否有解决方案或者这是一个错误?

编辑

事实证明这与WebView.enableSlowWholeDocumentDraw() 无关,我们仍在讨论这个问题。这是Bug Report。这是重现问题的Sample App

【问题讨论】:

    标签: android android-webview android-5.0-lollipop chromium


    【解决方案1】:

    我自己多年来一直在努力解决这个/类似的问题。终于找到了一个解决方案,由于某种原因,webView.draw(page.getCanvas()) 使用 KitKat 而不是 Lollipop 呈现整个内容(即使使用enableSlowWholeDocumentDraw())。
    但是,将 (webView.capturePicture()).draw(page.getCanvas())enableSlowWholeDocumentDraw() 结合使用确实适用于 Lollipop,尽管不推荐使用 capturePicture()
    最后一个可能需要注意的重要一点是,通常您会在 webView 加载其数据时看到许多对“onDraw”的调用,我发现使用 Lollipop 我的快照被过早地拍摄(在内容完全加载之前 - 令人讨厌的是 @987654326 @webViewClient 的回调方法不能保证这一点!) - 我的解决方案是有一个自定义 webView 并在 onDraw 方法中,将其添加为第一行:if(this.getContentHeight() == 0) return; 即除非有适当的内容,否则不要费心做任何绘图。 这样你就永远不应该得到一个空白页面快照——尽管从你的描述中听起来这可能不会影响你....

    【讨论】:

    • 感谢您的回答。我会对其进行测试并尽快回复您。
    • 我已经检查过了,它在 4.4 中工作,但在 API 5.0 和 5.1 中它崩溃了。我只能从 LogCat 得到这个。 Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 22023 (Thread-43812) 我认为这是内存问题。
    • 你有工作代码示例,我可以试一试并与我的比较吗?
    • 我以某种方式解决了 Crash,但它仍然是一样的,只绘制了可见部分。
    • 更新:它适用于 Android-L 中的 capturePicture() 以及 WebView.enableSlowWholeDocumentDraw(),但它不应该被使用,因为它已被弃用。我将该信息添加到问题单中。
    【解决方案2】:

    我是this question的作者。

    要解决这个问题,我必须调用WebView.enableSlowWholeDocumentDraw() 之前在你的片段中膨胀视图。在 Mikhail Naganov 的答案中,我看到您尝试了很多选择,但没有尝试过这个。下面是我在带有 WebView 的片段的 onCreateView() 方法中使用的代码。

    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle bundle){
        //Enable the drawing of the whole document for Lollipop to get the whole WebView
        if(Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP){
            WebView.enableSlowWholeDocumentDraw();
        }
        View view = inflater.inflate(R.layout.my_layout, parent, false);
    
       /* Rest of code */
    }
    

    真的没有别的了。如果这不起作用,那么它可能是一个错误,您应该按照 Mikhail 的建议进行报告。

    希望这会有所帮助!

    【讨论】:

    • 感谢您的回答。我尝试了这种替代方法,并在片段的 onCreate 和 onAttach 中调用了该方法。似乎没有任何效果。我认为这可能是一个错误。我将创建一张票并在此处分享链接。
    • HERE 是我的错误报告的链接
    • 我创建了一个简单的应用程序只是为了表明它不起作用。这可能真的很有帮助,如果你可以看看并告诉我是否有任何与你的情况不同的地方。 github.com/osayilgan/WebViewDemo
    • 我在片段中以同样的方式使用WebView.enableSlowWholeDocumentDraw()。但是,我没有在我的代码中使用 PDF 库,所以那里可能会有一些不同。当我有时间时,我会查看你的代码,看看我是否能找到任何错误。
    • 谢谢。我认为它与 PdfDocument 无关,因为它适用于 4.4,但不适用于以后的版本。
    【解决方案3】:
    if(Build.VERSION.SDK_INT>=21)    {
        WebView.enableSlowWholeDocumentDraw();
    }
    
    public void capture(WebView webView) {
        WebView lObjWebView = webView;
        lObjWebView.measure(MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
        lObjWebView.layout(0, 0, lObjWebView.getMeasuredWidth(), lObjWebView.getMeasuredHeight());
        Bitmap bm = Bitmap.createBitmap(lObjWebView.getMeasuredWidth(), lObjWebView.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
    
        Canvas bigcanvas = new Canvas(bm);
        Paint paint = new Paint();
        int iHeight = bm.getHeight();
        bigcanvas.drawBitmap(bm, 0, iHeight, paint);
        lObjWebView.draw(bigcanvas);
    
        if (bm != null) {
            try {
                File dir = new File(Environment.getExternalStorageDirectory() + "/" + "folder");
    
                Calendar lObjCalendar = Calendar.getInstance();
    
                int hour = lObjCalendar.get(Calendar.HOUR);
                int min = lObjCalendar.get(Calendar.MINUTE);
                int sec = lObjCalendar.get(Calendar.SECOND);
                int mili = lObjCalendar.get(Calendar.MILLISECOND);
                int day = lObjCalendar.get(Calendar.DAY_OF_YEAR);
                int month = lObjCalendar.get(Calendar.MONTH);
                int year = lObjCalendar.get(Calendar.YEAR);
    
                String realDate = "ERS_" + day + month + year + "_" + hour + min + sec + mili;
    
                if (dir.exists()) {
                    OutputStream fOut = null;
                    File file = new File(dir, realDate + ".jpg");
                    fOut = new FileOutputStream(file);
    
                    bm.compress(Bitmap.CompressFormat.PNG, 50, fOut);
                    fOut.flush();
                    fOut.close();
                    bm.recycle();
                }
                else {
    
                    if (dir.mkdir()) {
                        OutputStream fOut = null;
                        File file = new File(dir, realDate + ".jpg");
                        fOut = new FileOutputStream(file);
    
                        bm.compress(Bitmap.CompressFormat.PNG, 50, fOut);
                        fOut.flush();
                        fOut.close();
                        bm.recycle();
                    }
                    else {
                        ProjectUtil.showToast(WebPayment.this, "Problem in saving webview in external storage");
                    }
                }
            }
            catch (FileNotFoundException e) {
                ProjectUtil.showToast(WebPayment.this, "Problem in saving webview in external storage");
            }
            catch (IOException e) {
                ProjectUtil.showToast(WebPayment.this, "Problem in saving webview in external storage");
            }
            catch (Exception e) {
                ProjectUtil.showToast(WebPayment.this, "Problem in saving webview in external storage");
            }
        }
    }
    

    【讨论】:

    • 您是否阅读了该问题或任何其他给出的答案?或者您只是搜索“如何在 android 中绘制 webview”并复制/粘贴您找到的第一个答案?
    • 你可以试试我亲爱的朋友,如果你在任何地方得到这个答案,因为它的副本粘贴在你身上......让我们避免这种情况......这里的小鬼是什么......我也面临同样的问题..我用这种方式得到了解决方案..所以你至少可以试试这个..我正在保存整个网络视图的截图,你可以做你的一部分..前几行 capture() 将解决你的问题。
    • 我发现的唯一解决方案可以打印整个页面。
    【解决方案4】:

    在您的应用中创建任何 WebView 之前,您需要调用WebView.enableSlowWholeDocumentDraw()

    也就是说,如果您的静态布局中有 WebView,请确保在第一次调用 setContentView() 之前调用 WebView.enableSlowWholeDocumentDraw(),这会使用 WebView 扩展布局。

    还要确保您的 WebView 确实很大。例如,如果它的布局大小设置为match_parent,那么您的 WebView 将具有屏幕的大小,这就是将被捕获的内容。您需要为宽度和高度设置一些人为的高值。这个问题包含一个很好的说明:WebView.draw() not properly working on latest Android System WebView Update

    【讨论】:

    • 正如我在问题中所指出的,我知道最新的 android 版本中的这种变化,我已经从应用程序的 onCreate 中调用了静态“WebView.enableSlowWholeDocumentDraw()”方法,在基本 Activity 中的 setContentView 之前和在 Fragment 中膨胀我的视图之后。完全没有影响
    • 我明白了,很抱歉。然后可能值得仔细检查您的 WebView 确实有大尺寸,例如使用hierarchyviewer 此外,您可以检查您的应用程序在 KitKat 上的行为方式,其中始终呈现整个文档。
    • 我已经用 KitKat 进行了检查,它按预期工作。所以 WebView 的大小也应该没问题。
    • 那么它实际上可能是一个错误:) 请提交一个here 提供重现步骤。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多