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
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!
Make sure hardware-accelerated turned on within your Manifest XML.
<application android:hardwareAccelerated="true" ... />
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
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);
}
}