我想知道在显示内容之前是否有人有可靠的方法来获取webview的高度。我之前见过这个问题的变种。之前的答案建议使用以下代码:
viewTreeObserver = webview.getViewTreeObserver();
viewTreeObserver.addOnPreDrawListener(new OnPreDrawListener() {
int prevValue=0;
@Override
public boolean onPreDraw() {
int contentHeight = webview.getContentHeight();
Log.d("PreDraw","PreDrawCalled, Content Height: " + String.valueOf(contentHeight));
if ( contentHeight!= 0 && contentHeight==prevValue){
//Make sure the height has converged
int newPosition=(int)Math.round((webview.getContentHeight()*scrollPercent));
webview.scrollTo(0, newPosition);
webview.getViewTreeObserver().removeOnPreDrawListener(this);
}
prevValue=contentHeight;
return false;
}
});
我添加了prevValue变量。我的想法是检查以确保contentHeight的先前值与contentHeigh的当前值匹配,所以基本上我必须连续两次获得相同的高度。那甚至不起作用。以下是LogCat的输出。
04-05 19:24:04.851: D/PreDraw(18633): PreDrawCalled, Content Height: 0
04-05 19:24:04.853: D/PreDraw(18633): PreDrawCalled, Content Height: 0
04-05 19:24:04.867: D/PreDraw(18633): PreDrawCalled, Content Height: 8
04-05 19:24:04.882: D/PreDraw(18633): PreDrawCalled, Content Height: 8
04-05 19:24:04.898: D/PreDraw(18633): PreDrawCalled, Content Height: 8
04-05 19:24:04.915: D/PreDraw(18633): PreDrawCalled, Content Height: 8
04-05 19:24:04.932: D/PreDraw(18633): PreDrawCalled, Content Height: 8
04-05 19:24:04.949: D/PreDraw(18633): PreDrawCalled, Content Height: 8
04-05 19:24:04.966: D/PreDraw(18633): PreDrawCalled, Content Height: 8
04-05 19:24:04.982: D/PreDraw(18633): PreDrawCalled, Content Height: 2114
LogCat显示我连续多次获得contentHeight的相同值,所以我无法可靠地比较以前的值,除非我在一个循环中运行并放入一些标准,说我必须得到相同的答案10次连续的东西,但感觉hacky。我希望有更好的解决方案。
总体目标是在屏幕旋转时以及重新启动活动时保持webview滚动位置。我将scrollPercent变量存储在数据库中。
感谢您的帮助。
答案 0 :(得分:0)
webView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int height = webView.getHeight()
}
}
答案 1 :(得分:0)
我认为在尝试了一些不起作用的事情之后我终于找到了解决方案。似乎使用onPreDraw函数并等待内容高度不等于零的问题是,如果webview正在加载图像,则内容高度可能等于某个中间值。我也尝试过onPageFinished的WebViewClient方法,但即使页面仍在加载图像,也会触发。我还尝试覆盖WebView的invalidate方法,我不明白但也有同样的问题。对我有用的解决方案是实际调用javascript函数。 Javascript似乎有更多可用于检测页面加载的方法,其中还包括所有内容(包括图像已下载)的时间。我做了以下事情:
我在html中添加了一个javascript函数。对于某些人来说,这可能不是一个选项,但我可以完全控制html内容。
<script>
function loadAlert() {
var loadFlag;
if (document.readyState === "complete") {
loadFlag=1;
}else{
loadFlag=0;
}
window.pageload.sendToAndroid(loadFlag);
}
</script>
我不熟悉javascript,但基本上这个函数将变量loadFlag设置为0(如果页面未加载)和1加载时。当加载了包含图像的所有内容时,document.readyState等于完成。然后从Android查询此功能。
以下类被添加到android项目中。这只是附加到我正在使用的文件中的主片段类的末尾。这段代码是从之前的Stackoverflow帖子修改而来的。我不太明白这一点,但它为javascript设置了某种界面。
final class IJavascriptHandler {
IJavascriptHandler() {
}
// This annotation is required in Jelly Bean and later:
@JavascriptInterface
public void sendToAndroid(int loadFlag) {
// this is called from JS with passed value
jsLoadFlag=loadFlag;
}
}
以下代码放在onCreateView中(这是一个片段)。获取webview后,启用了javascript。最后一行设置了上面定义的接口。
webview = (WebView)v.findViewById(R.id.webView2);
webview.getSettings().setJavaScriptEnabled(true);
webview.addJavascriptInterface(new IJavascriptHandler(), "pageload");
其余代码设置了一个PreDraw监听器。从文档中,在将要绘制视图树时调用它,但这并不意味着加载了所有内容。这就是为什么有些帖子建议检查webview.getContentHeight何时不等于零的原因。我遇到的问题是,当图片加载时,我会得到一个非零数字。
第一个if语句检查以确保getContentHeight不等于零,并且webview进度为100,因此webview认为它已加载。我把javascript调用放在这个if语句中,以便最小化javascript调用。这也允许在旋转屏幕时对javascript调用进行一些延迟。我不确定在屏幕旋转时它究竟会被设置回零,但这会增加一些缓冲。
jsLoadFlag是一个在javascript接口类中设置的变量。它在整个文件中都可见。在onCreateView方法中将其设置为0很重要,否则在旋转时可能会保留它的先前值1.如果页面已完成加载,则此变量应该只为1。我想运行的代码仅在webview.getContentHeight!= 0和webview.getProgress == 100和jsLoadFlag == 1时运行。如果满足这些条件,则页面已加载。在IF语句中,我将webview滚动到正确的位置。
//Reset jsLoadFlag to account for rotations.
jsLoadFlag=0;
viewTreeObserver = webview.getViewTreeObserver();
viewTreeObserver.addOnPreDrawListener(new OnPreDrawListener() {
@Override
public boolean onPreDraw() {
if ( webview.getContentHeight()!= 0 && webview.getProgress()==100){
//This function sets the jsLoadFlag variable
webview.loadUrl("javascript:loadAlert();void(0)");
if(jsLoadFlag==1){
//Entire page including all pictures should have loaded so getContentHeight should be accurate
int newPosition=(int)Math.round((webview.getContentHeight()*scrollPercent));
webview.scrollTo(0, newPosition);
webview.getViewTreeObserver().removeOnPreDrawListener(this);
}
}
return false;
}
});