当WebView显示内容时是否有监听器?

时间:2010-10-31 21:08:16

标签: android events webview listener

使用WebViewClient和/或WebChromeClient,您可以在页面加载时获取侦听器,但有时在WebView中显示任何内容之前调用它,然后才显示任何内容。

确定WebView何时显示内容的有效方法是什么?

编辑:(试图更清楚)

当我在WebView中加载页面时,我想将滚动设置为特定位置。看起来在页面加载之前无法设置滚动位置,并且它具有实际的内容高度。因此,我尝试了两种不同的方法来确定页面何时完成加载,来自WebViewClient的onPageFinished()以及来自WebChromeClient的onProgressChanged()。这两个都告诉我页面何时加载完毕。

然而,问题是有时它会在页面显示之前被调用,因此页面没有高度,滚动调用什么都不做。

我正在尝试找到一种可靠的方法来确定页面何时可以滚动,即。当它有内容高度时。

我想我可以在完成加载后设置一个检查循环,以便在高度可用时继续查找,但这看起来很像黑客。希望有一种更清洁的方式。

11 个答案:

答案 0 :(得分:38)

我成功使用了Richard's answer with a PictureListener几年,但我不再推荐这是最佳解决方案。

这有两个原因:

  1. webView.setPictureListenerPictureListener均已弃用。
  2. 使用此侦听器将导致WebView经常分配新图片。这种分配很昂贵,这可能会对性能产生一些重大影响甚至导致JellyBean MR1上的本机崩溃。
  3. 相反,我建议创建WebView的子类并覆盖invalidate(),如下所示:

    @Override
    public void invalidate() {
        super.invalidate();
    
        if (getContentHeight() > 0) {
            // WebView has displayed some content and is scrollable.
        }
    }
    

    如果您仍想使用PictureListener方法,那么在完成后将setPictureListener恢复为null将获得更好的性能。

答案 1 :(得分:13)

编辑:自从我第一次发布此内容以来,此方法已在Android API 12中弃用。感谢Google!我将保留原来的答案:


是 - 有一个监听器知道内容何时完成加载。我不得不在我的项目中创建一个,所以我可以做一个启动画面,直到webview加载页面为止。

它被称为.setPictureListener。

例如:

mWebView.setPictureListener(new MyPictureListener());
//... and then later on....
class MyPictureListener implements PictureListener {

    @Override
    public void onNewPicture(WebView view, Picture arg1) {
      // put code here that needs to run when the page has finished loading and
      // a new "picture" is on the webview.      
    }    
} 

答案 2 :(得分:9)

这里建议的解决方案充其量只是hacky,而有一个非常干净的解决方案,in accordance with the Android docs

WebViewClient client = new WebViewClient() {
    @Override
    public void onPageFinished(WebView view, String url) {
        Log.d("MYAPP", "Page loaded");
    }
};
webView.setWebViewClient(client);

答案 3 :(得分:6)

我读了这个讨论,我也遇到了同样的问题。

我搜索了很多,但他们不是他们承诺的解决方案。

我不想使用已弃用的`onNewPicture`回调。

在我自己的情况下,我只需要在活动开始时恢复`WebView`滚动位置,我认为这是大多数情况,因为当活动任务堆栈进入后台时,Android会自动保存`WebView`状态,所以当它弹出到前景时,它看起来会一样。如果它在后台被杀死,我相信你会设法将状态保存在像`onPause`这样的Activity生命周期方法中。

所以,不是扩展`WebView`而是覆盖blah,blah,blah ......,而是使用Handler并发布模型。

private final Handler mHandler = new Handler();
// in onCreate
mHandler.postDelayed(new Runnable() {

                @Override
                public void run() {
                    if (mWebView.getContentHeight() > 0) {
                        mWebView.scrollTo(0, mLastPosition);
                        Log.d("scrolling", "true");
                        mHandler.removeCallbacks(this);
                    } else {
                        mHandler.postDelayed(this, 100);
                    }
                }
            }, 100);

此代码块将进行peridically检查是否可以操作WebView页面,如果是,它会进行滚动并删除回调,否则循环。 我对此进行测试并发现它通常不会花很长时间。

希望这有帮助!

答案 4 :(得分:2)

我创建了一个自定义视图扩展webview,它覆盖了“onSizeChanged”方法。在webview加载其中的所有内容后,会发生onSizeChanged。

答案 5 :(得分:1)

编辑:我不再推荐此解决方案,但我会将其留在此处以供参考。

如果这对其他人有帮助,我最终这样做的方法是通过继承WebView并覆盖computeVeritcalScrollExtent()方法。

@Override
protected int computeVerticalScrollExtent() {
    // do you checking here

    return super.computeVerticalScrollExtent();
}

只要WebView计算其垂直滚动条,就会调用此方法。但是,第一次调用getContentHeight() > 0时,这将是第一次显示内容。

答案 6 :(得分:1)

这不是问题的直接答案,但您也可以使用WebChromeClient。我发现它更可靠,我已将其配置为显示加载进度。在页面完全加载之前,WebView隐藏了ProgressBar,我遇到了同样的问题,我用WebView客户端替换了WebView。

我使用以下代码

final WebView wvMax = (WebView) findViewById(R.id.webViewTnSmax);
final ProgressBar pbMax = (ProgressBar) findViewById(R.id.progressBarTnSmax);

wvMax.setWebChromeClient(new WebChromeClient() {
    public void onProgressChanged(WebView view, int progress) {
        pbMax.setVisibility(View.VISIBLE);
        pbMax.setProgress(progress);
        if (progress == 100) {
            pbMax.setVisibility(View.GONE); // Make the bar disappear after URL is loaded
        }
    }

    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
        // do something
    }
});

答案 7 :(得分:1)

我知道它的旧但它可以帮助,这里的答案并不完美,我找到的最好的是在扩展的WebView上覆盖onDraw

  @Override
        protected void onDraw(Canvas canvas) {
    //do your math/stuff/magic/blackmagic/hackish here

            super.onDraw(canvas);
        }

所以每次向下滚动/向上滚动 每个fontZoomChange

几乎所有的东西(没有全部测试过)都会调用onDraw

我使用它来处理SeekBar作为Vertical ScrollBar

检查是否为null很重要,如果要避免无用的方法调用,则添加其他一些

答案 8 :(得分:1)

我已经修复了这个问题,创建了一个自定义视图,它覆盖onDraw方法并调用我自己的监听器。这是代码:

public class CustomWebView extends WebView{

public interface FinishedDrawListener{
    void onDrawFinished(WebView view, String url);
}

private FinishedDrawListener drawListener;

public CustomWebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
}

public CustomWebView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

public CustomWebView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public CustomWebView(Context context) {
    super(context);
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if(drawListener != null){
        drawListener.onDrawFinished(this, this.getUrl());
    }
}

public void setOnFinishedDrawListener(FinishedDrawListener listener){
    this.drawListener = listener;
}   

我认为这不是最好的方法,但它适用于我的应用程序。

答案 9 :(得分:0)

onLoadResource(WebView view, String url)

通知主机应用程序WebView将加载由给定URL指定的资源。

还不清楚目标是什么,但你可以试试

public void doUpdateVisitedHistory (WebView view, String url, boolean isReload)

我会“假设”页面在添加到历史记录之前已完成加载...

答案 10 :(得分:-1)

它适用于所有设备: - Load Web View ProgressDialog