Android WebView呈现为空白/白色,视图不';更新css更改或HTML更改时,动画不稳定
每当我更改css类时,这些更改并不总是出现。这似乎发生在我有一个触摸事件,它会在按钮上添加一个类似于向下类名的内容。按钮不会更新,页面上的其他任何内容也不会更新。它工作的时间非常不稳定。我还注意到,有时我的元素显示为白色,没有内容或任何东西。这太令人沮丧了 注意:Android WebView呈现为空白/白色,视图不';更新css更改或HTML更改时,动画不稳定,android,html,css,cordova,Android,Html,Css,Cordova,每当我更改css类时,这些更改并不总是出现。这似乎发生在我有一个触摸事件,它会在按钮上添加一个类似于向下类名的内容。按钮不会更新,页面上的其他任何内容也不会更新。它工作的时间非常不稳定。我还注意到,有时我的元素显示为白色,没有内容或任何东西。这太令人沮丧了 注意: Android 4.4+有一个更好的解决方案。这是一个叫做人行横道的替代品。它使用最新的铬试剂盒,非常棒。你可以在这里读到: 此外,自Android 4.4以来,似乎不再需要invalidate()解决方案,您可以使用其他更安全的解决
Android 4.4+有一个更好的解决方案。这是一个叫做人行横道的替代品。它使用最新的铬试剂盒,非常棒。你可以在这里读到: 此外,自Android 4.4以来,似乎不再需要
invalidate()
解决方案,您可以使用其他更安全的解决方案。我只会将这种invalidate()
方法作为最后的努力
我在回答我自己的问题,希望能帮助人们解决和我一样的问题 我已经尝试了几种方法来改善情况,甚至是臭名昭著的-
webkit转换:translate3d(0,0,0)代码>即使这样也不太管用
让我和你分享一下你的工作
首先,使用最新的API。我使用的是API 15。在您的AndroidManifest.xml
中,确保启用硬件加速。如果您的API版本不支持这一点,那么请转到下一位
如果您的版本确实支持它,您可以通过修改清单来启用它:
<application
...
android:hardwareAccelerated="true">
在body div位上添加您拥有的任何其他元素类型;您可能会排除图像、ul
、li
,等等。将此CSS样式应用于所有内容的原因只是反复尝试,我发现将其应用于所有内容似乎效果最好。对于更大的DOM树,您可能需要更加具体。但是,我不确定规格是什么
在实例化WebView
时,需要设置一些设置:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.loadUrl("file:///android_asset/www/index.html");
appView.getSettings().setRenderPriority(RenderPriority.HIGH);
appView.getSettings()
.setPluginState(WebSettings.PluginState.ON_DEMAND);
}
倒数第二,但很关键的一点:我正在阅读WebView
类的源代码,发现了这个关于强制重画的小评论。有一个静态最终布尔值
,当设置为true
时,将强制视图始终重新绘制。我对Java语法不是很在行,但我认为不能直接更改类的静态final属性。所以我最后做的就是这样扩展课程:
import org.apache.cordova.CordovaWebView;
import android.content.Context;
import android.graphics.Canvas;
public class MyWebView extends CordovaWebView {
public static final String TAG = "MyWebView";
public MyWebView(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// Warning! This will cause the WebView to continuously be redrawn
// and will drain the devices battery while the view is displayed!
invalidate();
}
}
请记住,我使用的是Cordova/PhoneGap,因此我必须从CordovaWebView
进行扩展。如果在onDraw方法中看到,则会调用invalidate
。这将导致视图不断重新绘制。但是,我强烈建议只在需要时添加逻辑来重新绘制
如果使用Cordova,还有最后一步。您必须告诉PhoneGap使用新的WebView
类,而不是他们自己的WebView
类。在MainActivity
类中,添加以下内容:
public void init(){
CordovaWebView webView = new MyWebView(MainActivity.this);
super.init(webView, new CordovaWebViewClient(this, webView), new CordovaChromeClient(this, webView));
}
就这样!试着运行你的应用程序,看看是否一切都顺利得多。在进行所有这些更改之前,页面将显示为白色,在再次点击屏幕之前,不会应用CSS更改,动画非常不稳定,甚至不明显。我应该提到的是,动画仍然波涛汹涌,但远没有以前那么波涛汹涌
如果有人对此有任何补充,请在下面发表评论。我总是对优化持开放态度;我充分意识到可能有更好的方法来做我刚才推荐的事情
如果我的上述解决方案不适用于您,您能否描述一下您的具体情况以及您在AndroidsWebView
中看到的结果
最后,我启用了这个答案作为一个“社区维基”,所以任何人和每个人都可以自由地进行调整
谢谢
编辑:
对于最新的PhoneGap,您需要使init()方法看起来更像这样:
body div {
-webkit-transform: translate3d(0,0,0);
}
public void init(){
CordovaWebView webView = new MyWebView(MainActivity.this);
super.init(webView, new IceCreamCordovaWebViewClient(this, webView), new CordovaChromeClient(this, webView));
}
我实施了凯尔的解决方案,解决了问题。然而,当android 4.0.4应用程序打开时,我注意到一个巨大的电池消耗。同样,在更改之后,我也有用户抱怨快捷键键盘不再适用于我的应用程序
我的应用程序中的每一个更改都是由用户操作触发的,因此我提出了一个修改版本,该版本仅在touchEvent之后触发invalidate():
Handler handler = new Handler();
public boolean onTouchEvent (MotionEvent event){
super.onTouchEvent(event);
handler.postDelayed(triggerInvalidate, 60);
handler.postDelayed(triggerInvalidate, 300);
return true;
}
private Runnable triggerInvalidate=new Runnable(){
public void run(){
invalidate();
}
};
从未使用Java进行过任何编程,因此可能有更好的解决方案。请参阅我的答案,其想法是将@Olivier的函数导出到JavaScript,以便您可以在合理的部分从JS触发失效。。。天哪,又是一个黑客!!:) re:重画问题,您可以通过从元素读取属性来强制重画
因此,假设你这样做:
$('#myElement').addClass('foo'); // youre not seeing this take effect
如果您在之后执行此操作:
$('#myElement').width();
这将迫使重新绘制
通过这种方式,您可以选择重新绘制整个页面,而不是像上面和其他地方指出的那样一直重新绘制整个页面,这是非常昂贵的——重写View.onDraw()
并调用View.invalidate
将导致电池性能不理想/应用程序性能下降。您还可以手动执行“无效化”
调用,每次x毫秒,如下所示
/**
* Due to bug in 4.2.2 sometimes the webView will not draw its contents after the data has loaded.
* Triggers redraw. Does not work in webView's onPageFinished callback for some reason
*/
private void forceWebViewRedraw()
{
mWebView.post(new Runnable() {
@Override
public void run()
{
mWebView.invalidate();
if(!isFinishing())
mWebView.postDelayed(this, 1000);
}
});
}
我尝试在
WebViewClient.onPageLoaded()
中调用invalidate,但似乎不起作用。虽然我的解决方案可能会更好,但它很简单,而且对我很有效(我只是显示一个twitter登录名)我遇到了这个问题,因为OnPageStarted和onPageFinished显示并隐藏了加载动画
因为注入JS会从原始网站上执行我的菜单和内容,并注意到在onPageFinished上注入JS会强制webview绘制内容。下面是一个可以在onPageFinished末尾添加内容的示例
view.loadUrl("javascript:(function() { var select = document.getElementsByClassName('something')[0]\r\n" +
" if(select)" +
" select.style.display = 'none';})()");
对我来说,这个问题只发生在三星设备上。我可以通过为我们禁用硬件加速来修复它
view.loadUrl("javascript:(function() { var select = document.getElementsByClassName('something')[0]\r\n" +
" if(select)" +
" select.style.display = 'none';})()");
webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
webView.clearCache(true);