2010-10-31 10 views
38

Al usar WebViewClient y/o WebChromeClient, puede obtener un detector para cuando se cargue la página; sin embargo, esto a veces se llama antes de que WebView tenga contenido, antes de que se muestre algo.¿Hay un oyente para cuando WebView muestra su contenido?

¿Cuál sería un método eficiente para determinar cuándo WebView ha mostrado su contenido?

Editar: (Tratando de ser más clara)

Cuando me carga una página en un WebView, que desea establecer el desplazamiento a una posición específica. Parece que la posición de desplazamiento no se puede establecer hasta que se cargue la página y tenga una altura de contenido real. Por lo tanto, he probado dos enfoques diferentes para determinar cuándo la página ha terminado de cargarse, onPageFinished() desde WebViewClient y también onProgressChanged() desde WebChromeClient. Ambos me dicen cuándo la página ha terminado de cargarse.

Sin embargo, el problema es que a veces se llama antes de que se muestre la página y, por lo tanto, la página no tiene altura y la llamada de desplazamiento no hace nada.

Estoy tratando de encontrar una manera sólida de determinar cuándo la página está lista para ser desplazada, es decir. cuando tiene su altura de contenido

Imagino que podría configurar un ciclo de comprobación después de que termine de cargar para seguir buscando cuando la altura está disponible, pero que parecía bastante el truco. Esperando que haya una manera más limpia.

Respuesta

38

He usado con éxito Richard's answer with a PictureListener desde hace unos años, pero ya no lo recomiendo como la mejor solución.

Esto es por dos razones:

  1. webView.setPictureListener y PictureListener están ambos en desuso.
  2. Al usar este detector, WebView asignará una nueva imagen con frecuencia. Esta asignación es costosa y esto puede tener algunos impactos significativos en el rendimiento o incluso causar bloqueos nativos en JellyBean MR1.

lugar de eso, se recomienda crear una subclase de vista Web e invalidar primordial(), así:

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

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

Si aún desea utilizar el método PictureListener, obtendrá un mejor rendimiento si setPictureListener de nuevo a cero después de que hayas terminado con eso.

+4

Esta es la mejor solución que he encontrado. Sin embargo, hay ocasiones en que no se llama a invalidate() cuando se actualiza el contenido de WebView en un WebView. Un caso inusual es cuando el contenido anterior se coloca en la parte superior cuando se llama a loadDataWithBaseURL, así que también agregué una llamada demorada para invalidar después de llamar a loadDataWithBaseURL. – Martin

+4

De hecho, la mejor solución. Agregar 'getProgress() == 100' me ayudó a asegurarme de que el contenido se procesara por completo. –

+0

Sé que esto es un poco tarde, pero novato aquí: ¿dónde pongo el código mencionado anteriormente? Donde quiera que lo coloque, Android Console dice que no es reconocido. – user4951834

0
onLoadResource(WebView view, String url) 

Notifique a la aplicación de host que la WebView cargará el recurso especificado por la url dada.

Aún no está claro de lo que es el objetivo aquí, pero usted puede tratar

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

Me "suponer" que la página ha terminado de cargarse antes de que se añade a la historia ...

+0

Gracias por la respuesta, pero ¿no le dice eso a la aplicación cuando el recurso específico está a punto de comenzar a cargarse cuando no se acaba de mostrar? Se solicita onLoadResource para cada recurso en la página en, todos se invocaron antes en el final de página. Lo que estoy buscando es algo que se llamaría después de la función de finalización de página, justo después de que la página se haya mostrado al usuario. – cottonBallPaws

+0

debe actualizar la pregunta para que quede más claro ... ¿tal vez alguien le dará una respuesta más adecuada? –

+1

agregó algunas ediciones a mi respuesta original –

2

I creó una vista personalizada que extiende la vista web, que anula el método "onSizeChanged". OnSizeChanged ocurre después de que la vista web carga todo en ella.

+2

Esto funciona perfectamente la primera vez que se carga una página, pero después de que se cargue la primera, nunca se vuelve a llamar para que no funcione si el usuario se va a mover a otras páginas. – cottonBallPaws

+0

Podría proporcionar algún código para esta respuesta, por favor – Fizzix

1

EDIT: Ya no recomiendo esta solución, pero la dejo aquí por el bien de la información.

En caso de que esto ayude a alguien más, la forma en que terminé haciendo esto fue subclasificando el WebView y reemplazando el método computeVeritcalScrollExtent().

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

    return super.computeVerticalScrollExtent(); 
} 

Se llamará cuando el WebView calcule su barra de desplazamiento vertical. Sin embargo, la primera vez que se llama donde getContentHeight() > 0, entonces será la primera vez que se muestre el contenido.

13

EDITAR: Desde que publiqué esto por primera vez, este método ha quedado obsoleto en Android API 12. ¡Gracias, Google! Dejaré la respuesta original en tacto:


Sí-- hay un oyente para saber cuándo el contenido ha terminado de cargarse. Tuve que crear uno en mi proyecto para poder hacer una pantalla de bienvenida que permaneció activa hasta que la vista web cargó la página.

Se llama .setPictureListener.

Por ejemplo:

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

Impresionante. Esto funciona exactamente como esperaba. Una advertencia para otros que usen esto sin embargo ... Se llama con bastante frecuencia a medida que se mueve por la página, así que asegúrese de que todo lo que sucede en el método onNewPicture sea rápido. – cottonBallPaws

+1

@Paul: Según entendí, este oyente se disparó cuando la vista web actualizó su "imagen", es decir, lo que se mostraba en la pantalla, independientemente de * qué * mostraba. Pero si es verdad que necesita tener al menos una imagen en la página, siempre podría agregar un simple .gif o .jpg de color sólido en algún lugar que se combinaría con el fondo y no sería visible para el usuario, pero podría causar esto oyente para disparar. Pero no puedo confirmar que sea necesario, ya que nunca he probado una vista web con solo texto. ¿Puede alguien más responder para aclarar? – Richard

+2

No, estaba equivocado. La "imagen" a la que hacen referencia los documentos de WebKit es la representación de los contenidos del navegador. Inicialmente estaba confundido sobre por qué la técnica anterior no funcionaba para mí, porque el evento no se activa a menos que la representación * realmente aparezca en la pantalla *. –

9

las soluciones sugeridas aquí son hacky, en el mejor, mientras que hay una solución perfectamente limpio, 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); 
+18

Me gustaría que esa fuera la respuesta, pero en mi experiencia en PageFinished puede ser, y es una gran parte del tiempo, invocado antes de que el contenido se muestre/se pueda desplazar/medir. Por lo tanto, si intenta desplazarse por el método onPageFinished, la altura del contenido podría ser 0. – cottonBallPaws

+1

Ah, a la derecha. En realidad, los documentos sugieren usar [onNewPicture (WebView, Picture)] (http: //developer.android.com/reference/android/webkit/WebView.PictureListener.html#onNewPicture \ (android.webkit.WebView,% 20android.graphics. Imagen \)), pero desde mi experiencia, no siempre se dispara. –

+1

Seguimiento: onNewPicture solo se activa si WebView está visible y se muestra dentro de los límites del dispositivo. Entonces, si desea usarlo para calcular las dimensiones antes de mostrar WebView, parece que esto no ayudará. –

-1

Su funcionamiento muy bien en todos los dispositivos: - Load Web View ProgressDialog

+0

Esto no funciona. La altura puede ser nula en onPageFinished. –

+0

Este enfoque es relevante solo si le interesa el hecho de que los datos de la página web se hayan cargado. No tiene nada que ver con dibujar/pintar los datos. –

6

He leído esta discusión, y estoy enfrentando el mismo problema también.

Busqué mucho, pero no son la solución que prometen.

Y no quiero utilizar la devolución de llamada obsoleta `onNewPicture`.

En mi propia situación solo necesito restaurar la posición de desplazamiento `WebView` cuando se inicia la actividad, y creo que es la mayor cantidad de casos desde que la pila de tareas de actividad se queda en segundo plano, Android guarda automáticamente el` WebView` estado, por lo que cuando aparezca en primer plano, se verá igual. Si se destruye cuando está en segundo plano, estoy seguro de que podrás guardar el estado en los métodos de ciclo de vida de la actividad como `onPause`.

Por lo tanto, en lugar de extender `WebView` y reemplazar bla, bla, bla ..., uso un manipulador y un modelo de publicación.

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

Este bloque de código se peridically comprobar si la página WebView puede ser manipulado, si es así, lo hace el movimiento en sentido vertical y retire la devolución de llamada, de lo contrario se realiza un bucle. Lo pruebo y lo averiguo usualmente no tomará mucho tiempo.

Espero que esto ayude!

+0

esto parece prometedor ... –

+0

Intenté WebViewClient.onPageFinished, WebChromeClient.onProgressChanged e incluso el obsoleto PictureListener.onNewPicture y todos eran poco confiables, pero este enfoque funciona bien. Sin embargo, si necesita borrar el contenido de WebView, establecer la URL en about: blank no devuelve el contentHeight a 0 como podría esperar. La única forma que pude encontrar para borrar el contenido y saber cuándo WebView está listo para aceptar nuevo contenido es crear un nuevo objeto WebView. – arlomedia

+0

Esto funciona en mi caso, pero en lugar de 'mWebView.getContentHeight()> 0', calculé la altura de la pantalla del dispositivo. Solo para ver que hay opciones. – sandalone

1

Esta no es una respuesta directa a la pregunta, pero alternativamente puede usar el WebChromeClient. Me parece más confiable y lo tengo configurado para mostrar el progreso de carga. Estaba teniendo el mismo problema con WebView que ocultaba ProgressBar antes de que la página estuviera completamente cargada y reemplacé WebView con el cliente WebView.

uso el siguiente código

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

Sé que es antiguo, pero puede ayudar, las respuestas aquí no son perfectamente de trabajo, lo mejor que he encontrado consiste en redefinir el onDraw en la vista Web extendido

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

      super.onDraw(canvas); 
     } 

por lo que cada desplazarse hacia abajo/arriba cada fontZoomChange

casi todo (aún no ha probado todos) llamará a la onDraw

Lo utilizo para trabajar con una barra de desplazamiento vertical SeekBar como

;)

es importante comprobar si nula, y añadir algunos otros si para evitar inútiles llamada al método

1

he fijado este problema crea una vista personalizada que anula el método onDraw y llama a mi propio oyente. Este es el código:

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

Creo que no es la mejor manera de hacerlo, pero funciona para mi aplicación.

Cuestiones relacionadas