objective-c - open - uiwebview tutorial
¿Cómo puedo saber cuándo finaliza(no carga) un UIWebView? (6)
Sé cuándo está listo para cargar ... (webViewDidFinishLoad), pero quiero usar
[webView.layer renderInContext:UIGraphicsGetCurrentContext()];
para crear una imagen desde UIWebView. Ocasionalmente obtengo la imagen antes de que webView termine su renderizado. Puedo usar performSelector para retrasar la obtención de la imagen, pero la cantidad de espera es arbitraria y frágil.
Esto puede depender del tipo de contexto de gráficos en el que necesite que se visualice la vista, pero puede llamar
- (void)drawRect:(CGRect)area forViewPrintFormatter:(UIViewPrintFormatter *)formatter
lo que aparentemente engaña a UIWebView para que piense que se está imprimiendo. Esto puede ayudar si su objetivo final es capturar la página completa. Recientemente tuvimos el problema de que, incluso si la página estaba cargada por completo, al llamar a plain old -drawRect: no representaba toda la página si parte de ella estaba fuera de la pantalla.
Si tiene acceso al archivo HTML y puede editarlo, simplemente agregue una variable especial que le dirá al código que la renderización está completa.
A continuación, utilice el método stringByEvaluatingJavaScriptFromString
para saber si debe iniciar algunas acciones o no.
El siguiente ejemplo es bastante sucio, pero espero que ayude y te dé la idea:
(void)webViewDidFinishLoad:(UIWebView *)webView
{
BOOL renderingDone = NO;
while (!(renderingDone == [[webView stringByEvaluatingJavaScriptFromString:@"yourjavascriptvariable"] isEqualToString:@"YES"]))
{
// the app will be "freezed" till the moment when your javascript variable will not get "YES" value
}
// do your stuff, rendering is done
}
Tuve un problema similar en una aplicación donde controlo completamente el contenido. Esto no funcionará si carga páginas arbitrarias desde la web, pero puede funcionar si conoce su estructura DOM de alto nivel y no cambia mucho .
Lo que funcionó para mí fue lo siguiente.
Tuve que buscar recursivamente la primera subvista de UIWebOverflowScrollView
del tipo UIWebOverflowScrollView
con un marco de (0, 0, 1024, 768)
. Si no puedo encontrar uno, esa es una señal segura de que el contenido aún no se ha procesado. Al encontrarlo, layer.sublayers.count
el layer.sublayers.count
esta vista . Cuando termina el renderizado, siempre termino con una o tres subcapas. Sin embargo, si el renderizado no ha finalizado, la vista de contenido siempre tuvo como máximo una subcapa.
Ahora, eso es específico de mi estructura DOM, pero es posible que invente una "prueba" similar si compara el árbol de la subcapa antes y después de la representación. Para mí, la regla general era que "la primera subvista recursivamente encontrada de tipo UIWebOverflowScrollView
tendrá al menos tres subcapas", para usted es probable que sea diferente.
De todos modos, tenga mucho cuidado si decide utilizar este enfoque, ya que aunque no será rechazado por mirar en la vista y la jerarquía de capas de UIWebView
, este tipo de comportamiento no es confiable y es muy probable que cambie en versiones futuras de iOS. . También puede ser inconsistente entre iOS 5 e iOS 6.
Por último, los fragmentos de código para MonoTouch que deberían ser fáciles de traducir al Objetivo C:
bool IsContentScrollView (UIScrollView scrollView)
{
return scrollView.Frame.Equals (new RectangleF (0, 0, 1024, 768));
}
[DllImport ("/usr/lib/libobjc.dylib")]
private static extern IntPtr object_getClassName (IntPtr obj);
public static string GetClassName (this UIView view) {
return Marshal.PtrToStringAuto (object_getClassName (view.Handle));
}
bool IsWebOverflowScrollView (UIScrollView scrollView)
{
return scrollView.GetClassName () == "UIWebOverflowScrollView";
}
IEnumerable<UIScrollView> ScrollViewsInside (UIView view)
{
foreach (var subview in view.Subviews) {
foreach (var scrollView in ScrollViewsInside (subview).ToList())
yield return scrollView;
if (subview is UIScrollView)
yield return (UIScrollView)subview;
}
}
bool CanMakeThumbnail {
get {
var scrollViews = ScrollViewsInside (this).Where (IsWebOverflowScrollView).ToList ();
var contentView = scrollViews.FirstOrDefault (IsContentScrollView);
// I don''t know why, but this seems to be a good enough heuristic.
// When the screen is black, either contentView is null or it has just 1 sublayer.
// This may *break* on any iOS updates or DOM changes--be extra careful!
if (contentView == null)
return false;
var contentLayer = contentView.Layer;
if (contentLayer == null || contentLayer.Sublayers == null || contentLayer.Sublayers.Length < 3)
return false;
return true;
}
}
¿Qué hay de usar el evento window.onload o jQuerys $ (document) .ready para activar la devolución de llamada shouldStartLoad?
Algo como:
$(document).ready(function(){
location.href = "app://do.something"
})
y en su UIWebViewDelegate haga algo como:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL *url = request.URL;
if([url.host isEqualToString:@"app"]){
//maybe check for "do.something"
//at this point you know, when the DOM is finished
}
}
Con este método puede reenviar todos los eventos posibles desde el código JS a su código obj-c.
Espero que ayude. ¡El ejemplo de código está escrito en el navegador y, por lo tanto, no está probado! ;-)
- (void)webViewDidFinishLoad:(UIWebView *)webView {
if (webView.isLoading)
return;
else
{
[self hideProgress];
}
}
if (webView.loading == YES)
{
//Load image
}
Algo así podría funcionar.