¿Cómo puedo saber cuándo se realiza una renderización de UIWebView (no se carga)?

Sé cuándo está hecho la carga … (webViewDidFinishLoad), pero quiero usar

[webView.layer renderInContext:UIGraphicsGetCurrentContext()]; 

para crear una image desde UIWebView. De vez en cuando obtengo la image antes de que la webView termine su renderizado. Puedo usar performSelector para retrasar la obtención de la image, pero la cantidad de espera es arbitraria y frágil.

Esto puede depender del tipo de context de charts en el que necesite la vista, pero puede llamar

 - (void)drawRect:(CGRect)area forViewPrintFormatter:(UIViewPrintFormatter *)formatter 

que aparentemente engaña al UIWebView para que piense que se está imprimiendo. Esto puede ayudar si su objective principal es capturar la página completa. Hemos tenido el problema recientemente en que, incluso si la página estaba completamente cargada, llamar a plain old -drawRect: no representaba toda la página si parte de ella estaba fuera de la pantalla.

Tuve un problema similar en una aplicación donde controlo completamente el contenido. Esto no funcionará si carga páginas arbitrarias de la web pero puede funcionar si conoce su estructura DOM de alto nivel y no cambia mucho .

Lo que funcionó para mí fue el siguiente.

Tuve que encontrar recursivamente la UIWebView de UIWebView del primer UIWebView con un marco de (0, 0, 1024, 768) . Si no encontré uno, ese fue un signo seguro de que el contenido aún no se ha traducido. Una vez que lo encontré, layer.sublayers.count esta vista . Cuando finaliza la renderización, siempre terminaría con una o tres subcapas. Sin embargo, si la representación no ha finalizado, la vista de contenido tenía a lo sumo una subcapa.

Ahora, eso es específico de mi estructura DOM, pero es posible que forme una "testing" similar si compara el tree de subcapa antes y después de la representación. Para mí, la regla de oro era "la primera subvista encontrada recursivamente del tipo UIWebOverflowScrollView tendrá al less tres subcapas", para usted es probable que sea diferente.

De todos modos, tenga mucho cuidado si decide usar este enfoque, ya que aunque no sea rechazado por mirar la vista y la jerarquía de capas de UIWebView , este tipo de comportamiento no es confiable y es muy probable que cambie en futuras versiones de iOS . Puede que también sea inconsistente entre iOS 5 y iOS 6 también.

Finalmente, fragments de código para MonoTouch que deberían ser sencillos 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 desencadenar callback shouldStartLoad?

Algo como:

 $(document).ready(function(){ location.href = "app://do.something" }) 

y en tu UIWebViewDelegate haz 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 events posibles desde el código JS a su código obj-c.

Espero que ayude. El código de muestra está escrito en el browser y, por lo tanto, no se ha probado. D

 - (void)webViewDidFinishLoad:(UIWebView *)webView { if (webView.isLoading) return; else { [self hideProgress]; } } 

Si tiene acceso al file HTML y puede editarlo, simplemente agregue alguna variable especial que le indicará al código que se ha realizado.
Luego use el método stringByEvaluatingJavaScriptFromString para saber si debe iniciar algunas acciones o no.
El siguiente ejemplo es bastante sucio, pero espero que te 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 } 
 if (webView.loading == YES) { //Load image } 

Algo así podría funcionar.