Android WebView Hardware Rendering Weird Artifact Issue

前端 未结 4 1926
情书的邮戳
情书的邮戳 2020-12-14 20:57

On some devices like the Nexus 7 or Samsung Galaxy Nexus (possibly others), I noticed this issue (See picture). This is running on Hardware Acceleration Mode in a WebView. H

相关标签:
4条回答
  • 2020-12-14 21:29

    Thanks to Delyan for solving the issue. How he told me to solve it was to add -webkit-transform: translate3d(0,0,0) to all parts that move.

    KUDOS DELYAN!

    0 讨论(0)
  • 2020-12-14 21:33

    Make sure hardware-accelerated turned on within your Manifest XML.

    <application android:hardwareAccelerated="true" ... />
    
    0 讨论(0)
  • 2020-12-14 21:35

    After a number of false starts, I could only find the hackish solution of switching between hardware rendering and software rendering depending on the current scaling.

    Basically the idea is that rendering artifacts would only show up after a certain scaling, so we can safely use hardware rendering before this threshold is crossed and switch to slower-but-correct software rendering when larger scaling is used. The scaling threshold is > 1.67 on N7 though you may have to check on Galaxy Nexus to see if this value is universal. In my experience there are quite a number of issues with WebView across every version of Android, so this may be the best solution currently until everyone updated to 4.3...

     webView.setWebViewClient(new WebViewClient() {
    
                    @Override
                    public void onScaleChanged(WebView view, float oldScale,
                            float newScale) {
                    //4.3 SDK required, or change Build.VERSION_CODES.JELLY_BEAN_MR2 to 18
                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
                        if (newScale > 1.7f) {
                            if (webView.getLayerType() != View.LAYER_TYPE_SOFTWARE) {
                                webView.setLayerType(View.LAYER_TYPE_SOFTWARE,
                                        null);
                            }
                        } else {
                            if (webView.getLayerType() != View.LAYER_TYPE_HARDWARE) {
                                webView.setLayerType(View.LAYER_TYPE_HARDWARE,
                                        null);
                            }
                        }
                    }
                    }
    });
    

    Note that onScaleChanged() would be called multiple times, sometimes crossing the threshold with a single zoom (using zoom in/out button), so you should add some logic to reduce the number of webView.setLayerType() calls to one-per-zoom event to reduce hardware/software rendering artifacts that would be displayed for a brief interval

    0 讨论(0)
  • 2020-12-14 21:47

    This is a race-condition bug in WebView. Where the rendering of the page becomes out of sync with the actual view of the page.

    The normal cause is because you are handling rotation with android:configChanges in your <activity> tag in the AndroidManifest.xml file. Recreating the WebView on rotation will resolve this issue, but this itself has other problems attached to it.

    Their are two solutions I know of. I would not recommend you keep using android:configChanges as its usually detrimental if you don't really know what this change means to your application. If you absolutely need to keep the android:configChanges, there is a solution. You can create your own custom View which inherits from a WebView. Simply override onConfigurationChanged and don't forward it on to the super class.. in this case that's the WebView. I have included code below as an example of this.

    But the more truer and correct approach is to correct handle the saving and restoring of the WebView's state. If you hunt around online you will find a multitude of solutions for this problem. Here is a particually good one. http://www.devahead.com/blog/2012/01/preserving-the-state-of-an-android-webview-on-screen-orientation-change/

    import android.content.Context;
    import android.content.res.Configuration;
    import android.util.AttributeSet;
    import android.webkit.WebView;
    
    
    public class MyWebView extends WebView
    {
        public MyWebView(Context context)
        {
            super(context);
        }
    
        public MyWebView(Context context, AttributeSet attrs)
        {
            super(context, attrs);
        }
        public MyWebView(Context context, AttributeSet attrs, int defStyle)
        {
            super(context, attrs, defStyle);
        }
    
        @Override
        protected void onConfigurationChanged(Configuration newConfig)
        {
            // NOTE: We don't want to call this
            // super.onConfigurationChanged(newConfig);
        }
    }
    
    0 讨论(0)
提交回复
热议问题