Есть ли слушатель, когда WebView отображает его содержимое?

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

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

Изменить: (Попытка быть более понятной)

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

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

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

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

Ответ 1

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

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

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

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

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

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

Если вы все еще хотите использовать метод PictureListener, вы получите лучшую производительность, если вы установите для параметраPictureListener значение null после того, как вы закончите с ним.

Ответ 2

EDIT: поскольку я впервые разместил это, этот метод устарел в 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.      
    }    
} 

Ответ 3

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

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

Ответ 4

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

Я много искал, но они не являются решением, которым они обещают быть.

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

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

Итак, вместо расширения `WebView` и переопределения blah, blah, blah..., я использую модель Handler и post.

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, если это так, он выполняет прокрутку и удаляет обратный вызов, в противном случае он будет зациклен. Я проверяю это и узнаю, что он обычно не займет много времени.

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

Ответ 5

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

Ответ 6

EDIT: я больше не рекомендую это решение, но я оставлю его здесь для информации.

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

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

    return super.computeVerticalScrollExtent();
}

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

Ответ 7

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

Ответ 8

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

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

            super.onDraw(canvas);
        }

поэтому каждая прокрутка вниз/вверх каждый fontZoomChange

почти все (не проверили все) вызовет onDraw

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

;)

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

Ответ 9

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

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

Ответ 10

onLoadResource(WebView view, String url)

Сообщите хост-приложению, что WebView загрузит ресурс, указанный данным URL.

Все еще не ясно, что цель здесь, но вы можете попробовать

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

Я бы "предположил", что страница завершила загрузку до ее добавления в историю...