web-dev-qa-db-fra.com

Existe-t-il un écouteur lorsque la WebView affiche son contenu?

En utilisant WebViewClient et/ou WebChromeClient, vous pouvez obtenir un écouteur lorsque la page est chargée, mais cela est parfois appelé avant que le WebView ne contienne du contenu, avant qu'il n'ait affiché quoi que ce soit.

Quelle serait une méthode efficace pour déterminer quand la WebView a affiché son contenu?

Edit: (Essayer d'être plus clair)

Lorsque je charge une page dans une WebView, je souhaite définir le défilement sur une position spécifique. Il semble que la position de défilement ne peut pas être définie tant que la page n'est pas chargée et qu'elle n'a pas une hauteur de contenu réelle. J'ai donc essayé deux approches différentes pour déterminer quand la page a fini de se charger, onPageFinished () à partir de WebViewClient et également onProgressChanged () à partir de WebChromeClient. Ces deux me disent quand la page a fini de se charger.

Cependant, le problème est que parfois elle est appelée avant que la page ne soit affichée et donc la page n'a pas de hauteur et l'appel de défilement ne fait rien.

J'essaie de trouver un moyen solide de déterminer quand la page est prête à défiler, c'est-à-dire. quand il a sa hauteur de contenu.

J'imagine que je pourrais configurer une boucle de vérification une fois le chargement terminé pour continuer à chercher lorsque la hauteur est disponible, mais cela semblait être un hack. En espérant qu'il existe un moyen plus propre.

40
cottonBallPaws

J'ai utilisé avec succès la réponse de Richard avec un PictureListener pendant quelques années, mais je ne recommande plus cela comme la meilleure solution.

C'est pour deux raisons:

  1. webView.setPictureListener et PictureListener sont tous deux obsolètes.
  2. L'utilisation de cet écouteur entraînera l'allocation fréquente d'une nouvelle image par WebView. Cette allocation est coûteuse et cela peut avoir des impacts significatifs sur les performances ou même provoquer des plantages natifs sur JellyBean MR1.

Au lieu de cela, je recommande de créer une sous-classe de WebView et de remplacer invalidate () comme ceci:

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

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

Si vous souhaitez toujours utiliser la méthode PictureListener, vous obtiendrez de meilleures performances si vous redéfinissezPictureListener sur null après avoir terminé.

38
cottonBallPaws

EDIT: depuis que j'ai posté cela pour la première fois, cette méthode a été déconseillée dans Android API 12. Merci, Google! Je vais laisser la réponse originale en tact:


Oui - il y a IS un auditeur pour savoir quand le contenu a fini de se charger. J'ai dû en créer un sur mon projet pour pouvoir faire un écran de démarrage qui restait en place jusqu'à ce que la vue Web ait chargé la page .

Il s'appelle .setPictureListener.

Par exemple:

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.      
    }    
} 
14
Richard

Les solutions suggérées ici sont au mieux hacky, alors qu'il existe une solution parfaitement propre, conformément aux Android docs :

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

J'ai lu cette discussion et je fais face au même problème aussi.

J'ai beaucoup cherché, mais ce n'est pas la solution qu'ils promettent.

Et je ne veux pas utiliser le rappel obsolète `onNewPicture`.

Dans ma propre situation, je n'ai besoin que de restaurer la position de défilement de `WebView` lorsque l'activité est démarrée, et je pense que c'est le plus souvent depuis que lorsque la pile de tâches d'activité passe en arrière-plan, Android automatiquement enregistrer l'état `WebView`, donc quand il apparaît au premier plan, il aura la même apparence. S'il est tué en arrière-plan, je suis sûr que vous réussirez à enregistrer l'état dans les méthodes de cycle de vie d'activité comme` onPause`.

Donc, au lieu d'étendre `WebView` et de remplacer blah, blah, blah ..., j'utilise un gestionnaire et un post-modèle.

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

Ce bloc de code vérifiera péridiquement si la page WebView peut être manipulée, si c'est le cas, il fait le défilement et supprime le rappel, sinon il boucle. Je teste cela et je trouve que cela ne prendra généralement pas très longtemps.

J'espère que cela t'aides!

7
user3103871

J'ai créé une vue personnalisée étend la vue Web, qui remplace la méthode "onSizeChanged". OnSizeChanged se produit une fois que la vue Web a tout chargé.

2
OatsMantou

Ce n'est pas une réponse directe à la question posée, mais vous pouvez également utiliser WebChromeClient. Je le trouve plus fiable et je l'ai configuré pour afficher la progression du chargement. J'avais le même problème avec WebView masquant la barre de progression avant que la page ne soit complètement chargée et j'ai remplacé WebView par le client WebView.

J'utilise le code suivant

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
theczechsensation

Je connais son ancien mais il peut AIDER, les réponses ici ne fonctionnent pas parfaitement, le mieux que j'ai trouvé est de remplacer le onDraw sur le WebView étendu

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

            super.onDraw(canvas);
        }

donc chaque défilement vers le bas/haut chaque police

presque tout (n'a pas tout testé) appellera onDraw

je l'utilise pour travailler avec une barre de recherche comme barre de défilement verticale

;)

il est important de vérifier s'il est nul et d'ajouter quelques autres pour éviter un appel de méthode inutile

1
Senhor Obvio

J'ai résolu ce problème en créant une vue personnalisée qui remplace la méthode onDraw et en appelant mon propre écouteur. Voici le code:

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

Je pense que ce n'est pas la meilleure façon de le faire, mais cela fonctionne pour mon application.

1
emaleavil

EDIT: je ne recommande plus cette solution, mais je vais la laisser ici pour information.

Au cas où cela aiderait quelqu'un d'autre, j'ai fini par le faire en sous-classant WebView et en remplaçant la méthode computeVeritcalScrollExtent().

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

    return super.computeVerticalScrollExtent();
}

Cela sera appelé à chaque fois que WebView calcule sa barre de défilement verticale. Cependant, la première fois qu'il est appelé où la getContentHeight() > 0, ce sera la première fois que le contenu est affiché.

1
cottonBallPaws
onLoadResource(WebView view, String url)

Informez l'application hôte que WebView chargera la ressource spécifiée par l'URL donnée.

Je ne sais toujours pas quel est l'objectif ici, mais vous pourriez essayer

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

Je "suppose" que le chargement de la page est terminé avant d'être ajouté à l'historique ...

0
Aaron Saunders