scrollTo()之后的Android WebView损坏图形

scrollTo()之后的Android WebView损坏图形,android,scroll,webview,bitmap,draw,Android,Scroll,Webview,Bitmap,Draw,我正在编写一个应用程序,我需要一个WebView作为Android服务的web渲染机制。 因此WebView永远不会附加到窗口。 但是,通过手动测量和布局视图(视图组),然后在其上绘制位图,我可以生成页面的快照,而无需将其放入视图层次结构中 问题是,一旦我调用它来scrollTo(),视图就不会绘制隐藏在滚动之前的页面部分并对其进行裁剪,类似这样 layout(mWebView, maxWidth, maxHeight); // page is loaded mWebView.scrollTo(

我正在编写一个应用程序,我需要一个WebView作为Android服务的web渲染机制。 因此WebView永远不会附加到窗口。 但是,通过手动测量和布局视图(视图组),然后在其上绘制位图,我可以生成页面的快照,而无需将其放入视图层次结构中

问题是,一旦我调用它来scrollTo(),视图就不会绘制隐藏在滚动之前的页面部分并对其进行裁剪,类似这样

layout(mWebView, maxWidth, maxHeight);
// page is loaded
mWebView.scrollTo(...);
// here I've tried number of things like mWebView.invalidate(), mWebView.requestLayout() or mWebView.refreshDrawableState()
final Bitmap bitmap = capture(mWebView);

WebView在使用以下方法请求页面加载之前很久就被布置好了

private void layout(
        @NonNull final WebView webView, final int targetWidth, final int targetHeight) {
    webView.measure(
            View.MeasureSpec.makeMeasureSpec(targetWidth, View.MeasureSpec.AT_MOST),
            View.MeasureSpec.makeMeasureSpec(targetHeight, View.MeasureSpec.AT_MOST));

    webView.layout(0, 0, targetWidth, targetHeight);
}
位图是使用以下代码捕获的

private Bitmap capture(
        @NonNull final WebView webView) {
    webView.setDrawingCacheEnabled(true);
    webView.buildDrawingCache();

    final Bitmap bitmap = Bitmap.createBitmap(
            webView.getWidth(), webView.getHeight(), Bitmap.Config.ARGB_8888);

    final Canvas canvas = new Canvas(bitmap);
    webView.draw(canvas);

    webView.setDrawingCacheEnabled(false);

    return bitmap;
}
整个过程是这样的

layout(mWebView, maxWidth, maxHeight);
// page is loaded
mWebView.scrollTo(...);
// here I've tried number of things like mWebView.invalidate(), mWebView.requestLayout() or mWebView.refreshDrawableState()
final Bitmap bitmap = capture(mWebView);
重要提示:当我在Web视图中加载页面时,该页面通常连接到活动中的窗口,Web视图会滚动到我想要的位置,页面会很好地显示出来

有什么区别?这与android将WebView附加到活动窗口时对WebView所做的操作有何不同

mWebView.scrollTo(...);

webView.setDrawingCacheEnabled(true);
webView.buildDrawingCache();//write these lines before posting the capture event

new Handler.post(){
    new Runnable(){
        public void run(){
            final Bitmap bitmap = capture(mWebView);
        }
    }
}

它可能会解决您的问题…:-)

我终于找到了这个问题的根本原因。 我创建位图的机制依赖于WebView启用了图形缓存并在画布上绘制自己这一事实

图形缓存将被启用,但在滚动更改后从未更新,因为只有视图状态更改

看起来,由于我正在为视图渲染启用硬件加速,所以我需要做的就是启用图形缓存,并在设置滚动位置后,在需要新位图时使用它(我甚至不需要为此目的使视图无效)

因此,解决方案如下:

public void init() {
    mWebView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
    mWebView.setDrawingCacheEnabled(true);
    // (layout the view)
}

public void capture(...) {
    mWebView.scrollTo(...);
    final Bitmap capturedBitmap = mWebView.getDrawingCache();
    // do sth with the bitmap
    // ...
}

因此,这一切都要简单得多。

我确信
WebView
采用了优化,如果它检测到自己没有连接到窗口,就不会重新绘制自己。您是否尝试在WebView上调用
invalidate()
?也许这会迫使你重新画一张完整的图……谢谢你的回复。是的,我有。我尝试过requestLayout(),也尝试过在页面加载后的短时间(~1s)超时后执行此操作。我已经看过了,很难准确理解那里发生了什么(WebView、WebViewChromium等),但我可以告诉您,某些绘图/滚动功能要求WebView在UI线程上运行/连接到视图层次结构。此外,类似于
View.invalidate()
这适用于常规情况。当我只调整webview滚动位置时,它不起作用。感谢回复,但这没有帮助。