Есть ли прослушиватель, когда WebView отображает его содержимое? - PullRequest
40 голосов
/ 01 ноября 2010

Используя WebViewClient и / или WebChromeClient, вы можете получить прослушиватель, когда страница загружена, однако иногда это вызывается до того, как в WebView есть какой-либо контент, прежде чем он что-либо отобразит.

Каким будет эффективный метод определения того, когда WebView отображает свой контент?

Редактировать: (Пытаясь быть более ясным)

Когда я загружаю страницу в WebView, я хочу установить прокрутку на определенную позицию. Кажется, что положение прокрутки нельзя установить до тех пор, пока страница не будет загружена и у нее не будет фактической высоты содержимого. Итак, я попробовал два разных подхода к определению, когда страница закончила загрузку, onPageFinished () из WebViewClient и также onProgressChanged () из WebChromeClient. Оба из них говорят мне, когда страница закончила загрузку.

Однако проблема в том, что иногда он вызывается до отображения страницы, и поэтому страница не имеет высоты, а вызов прокрутки ничего не делает.

Я пытаюсь найти надежный способ определить, когда страница готова к прокрутке, т.е. когда он имеет высоту содержимого.

Я полагаю, я мог бы настроить цикл проверки после того, как он закончил загрузку, чтобы продолжать искать, когда высота доступна, но это выглядело как хак. Надеюсь, что есть более чистый путь.

Ответы [ 11 ]

38 голосов
/ 04 февраля 2013

Я успешно использовал ответ Ричарда с PictureListener в течение нескольких лет, но я больше не рекомендую это как лучшее решение.

Это по двум причинам:

  1. webView.setPictureListener и PictureListener оба устарели.
  2. При использовании этого прослушивателя WebView будет часто выделять новое изображение.Это распределение является дорогостоящим, и это может оказать значительное влияние на производительность или даже вызвать собственные сбои в JellyBean MR1.

Вместо этого я рекомендую создать подкласс WebView и переопределить invalidate () следующим образом:

@Override
public void invalidate() {
    super.invalidate();

    if (getContentHeight() > 0) {
        // WebView has displayed some content and is scrollable.
    }
}

Если вы по-прежнему хотите использовать метод PictureListener, вы получите более высокую производительность, если после установки с ним снова установите null после возврата.

14 голосов
/ 09 февраля 2011

РЕДАКТИРОВАТЬ: С тех пор как я впервые опубликовал это, этот метод устарел в Android API 12. Спасибо, Google!Я оставлю исходный ответ в такте:


Да - есть слушатель, который знает, когда контент закончил загружаться.Мне нужно было создать его в моем проекте, чтобы я мог создать заставку, которая работала до тех пор, пока веб-просмотр не загрузил страницу.

Она называется .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.      
    }    
} 
8 голосов
/ 05 мая 2011

Предлагаемые здесь решения в лучшем случае являются хакерскими, в то время как есть совершенно чистое решение, в соответствии с документацией для Android :

WebViewClient client = new WebViewClient() {
    @Override
    public void onPageFinished(WebView view, String url) {
        Log.d("MYAPP", "Page loaded");
    }
};
webView.setWebViewClient(client);
7 голосов
/ 15 декабря 2013

Я прочитал это обсуждение, и я столкнулся с той же проблемой.

Я много искал, но это не то решение, которое обещают.

И я не знаюЯ не хочу использовать устаревший обратный вызов onNewPicture.

В моей собственной ситуации мне нужно только восстанавливать позицию прокрутки WebView при запуске действия, и я думаю, что это в большинстве случаев, так как когдаСтек заданий активности переходит в фоновый режим, Android автоматически сохраняет состояние `WebView`, поэтому, когда он выходит на передний план, он будет выглядеть так же.Если это будет убито в фоновом режиме, я уверен, что вам удастся сохранить состояние в методах жизненного цикла Activity, таких как `onPause`.

Так что вместо расширения` WebView` и переопределения бла, бла, бла..., я использую обработчик и пост-модель.

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);

Этот блок кода будет периодически проверять, можно ли манипулировать страницей WebView, если это так, он выполняет прокрутку и удаляет обратный вызов, в противном случае он зацикливается,Я проверяю это и выясняю, что обычно это не займет много времени.

Надеюсь, это поможет!

2 голосов
/ 21 ноября 2010

Я создал собственное представление, расширяющее веб-представление, которое переопределяет метод "onSizeChanged". OnSizeChanged происходит после того, как веб-просмотр загружает в него все.

1 голос
/ 07 апреля 2016

Я исправил эту проблему, создав пользовательское представление, которое переопределяет метод 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;
}   

Я думаю, что это не лучший способ сделать это, но он работает для моего приложения.

1 голос
/ 20 августа 2015

Я знаю его старый, но он может ПОМОЧЬ, ответы здесь не совсем работают, лучшее, что я нашел, это переопределить onDraw в Extended WebView

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

            super.onDraw(canvas);
        }

, так что каждый переход вниз / вверх каждыйfontZoomChange

почти все (не проверял все) будут вызывать onDraw

, я использую это для работы с SeekBar как Vertical ScrollBar

;)

важно проверить, если ноль, и добавить некоторые другие, чтобы избежать бесполезного вызова метода

1 голос
/ 25 апреля 2014

Это не прямой ответ на заданный вопрос, но вы также можете использовать 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
    }
});
1 голос
/ 11 января 2011

РЕДАКТИРОВАТЬ: я больше не рекомендую это решение, но я оставлю его здесь для информации.

В случае, если это поможет кому-то еще, в конечном итоге я сделал это путем создания подкласса WebView и переопределения метода computeVeritcalScrollExtent().

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

    return super.computeVerticalScrollExtent();
}

Это будет вызываться каждый раз, когда WebView вычисляет свою вертикальную полосу прокрутки. Тем не менее, когда он вызывается в первый раз, когда getContentHeight() > 0, тогда это будет первый раз, когда отображается контент.

0 голосов
/ 11 октября 2012

Работает нормально на всех устройствах: - Загрузить веб-просмотр ProgressDialog

...