UIWebView con Barra de Progreso


Hola soy nuevo en la programación y estoy tratando de hacer mi primera aplicación para iPhones en Xcode. Mi aplicación contiene un botón que abre un UIWebView cuando se presiona y carga una página de inicio. Ahora también quiero agregar una Vista de progreso a la vista WEB como Safari también utiliza, que indica el progreso de la carga de la página. ¿Cómo puedo hacer eso?
Mi código hasta ahora para cargar la URL en el UIWebView:

.h

IBOutlet UIWebView *webView;

.m

- (void)viewDidLoad
{
[webView loadRequest:[NSURLRequest requestWithURL: [NSURL URLWithString:@"http:/www.google.com/"]]];

Gracias por su ayuda!

Author: rmaddy, 2014-01-21

7 answers

Para tener un UIProgressView preciso, necesitas tener alguna tarea que:

  • Puede obtener información mientras no esté completa
  • Cuantificar su "integridad" como un porcentaje basado en esa información.

Ahora que estás cargando tu UIWebView, eso no es posible. Y Apple tampoco lo hace. Apple a menudo utiliza falsos UIProgressViews para darle algo para mirar mientras se carga la página. Mail también utiliza vistas de progreso falsas. Ve a probarlo por ti mismo. Así es como Las vistas de progreso falsas de Apple funcionan:

  • La vista de progreso comienza a moverse a una velocidad lenta y constante
  • Si la tarea termina antes de que se complete la barra, de repente se comprime en el resto al 100% antes de desaparecer
  • Si la tarea toma mucho tiempo, la vista de progreso se detendrá al 95% y permanecerá allí hasta que la tarea esté completa.

Para lograr esto, tendrá que animar el progressView manualmente. Usted podría subclase, pero que probablemente sería un poco avanzado para ti. La forma más sencilla sería esta:

En MyViewController.h

@interface myViewController : UIViewController {
     BOOL theBool;
     //IBOutlet means you can place the progressView in Interface Builder and connect it to your code
     IBOutlet UIProgressView* myProgressView;
     NSTimer *myTimer;
}
@end

En MyViewController.m

#import "myViewController.h"
@implementation myViewController
- (void)webViewDidStartLoad:(UIWebView *)webView{
     myProgressView.progress = 0;
     theBool = false;
     //0.01667 is roughly 1/60, so it will update at 60 FPS
     myTimer = [NSTimer scheduledTimerWithTimeInterval:0.01667 target:self selector:@selector(timerCallback) userInfo:nil repeats:YES];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView{
     theBool = true;
}
-(void)timerCallback {
    if (theBool) {
         if (myProgressView.progress >= 1) {
              myProgressView.hidden = true;
              [myTimer invalidate];
         }
         else {
              myProgressView.progress += 0.1;
         }
    }
    else {
         myProgressView.progress += 0.05;
         if (myProgressView.progress >= 0.95) {
              myProgressView.progress = 0.95;
         }
    }
}
@end

Luego, cuando se complete su tarea, establezca theBool = true; y la vista de progreso se encargará de sí misma. Cambie los valores en la instrucción if para controlar la velocidad de la animación.

 70
Author: WolfLink,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-06 11:48:36

Swift 2.2

class ViewController: UIViewController,UIWebViewDelegate {

    @IBOutlet weak var webView: UIWebView!
    @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
    @IBOutlet weak var myProgressView: UIProgressView!

    var myTimer = NSTimer()
    var theBool = Bool()

    override func viewDidLoad() {
        super.viewDidLoad()

        let url = NSURL(string: "https://www.youtube.com")
        let request = NSURLRequest(URL: url!)
        activityIndicator.hidesWhenStopped = true
        activityIndicator.startAnimating()
        webView.loadRequest(request)

    }
    func timerCallback(){
        if theBool {
            if myProgressView.progress >= 1 {
                myProgressView.hidden = true
                myTimer.invalidate()
            }else{
                myProgressView.progress += 0.1
            }
        }else{
            myProgressView.progress += 0.05
            if myProgressView.progress >= 0.95 {
                myProgressView.progress = 0.95
            }
        }
    }

    func webViewDidStartLoad(webView: UIWebView) {
        activityIndicator.startAnimating()
        myProgressView.progress = 0
        theBool = false
        myTimer =  NSTimer.scheduledTimerWithTimeInterval(0.01667,target: self,selector: #selector(ViewController.timerCallback),userInfo: nil,repeats: true)
    }
    func webViewDidFinishLoad(webView: UIWebView) {
        activityIndicator.stopAnimating()
        theBool = true
    }
}
 5
Author: ZAFAR007,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-15 20:09:19

Seguí la respuesta de Wolflink y encontré el mismo problema al no tener el progressView animado.

Después de leer la referencia de la clase NSTimer:

Https://developer.apple.com/library/Mac/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/Reference/NSTimer.html#//apple_ref/occ/clm/NSTimer/timerWithTimeInterval:target:selector:userInfo:repeats:

En Discusión puedes leer: "Debe agregar el nuevo temporizador a un bucle de ejecución, utilizando addTimer:forMode:. "

Así que agregué

[[NSRunLoop currentRunLoop] addTimer:myTimer forMode:NSDefaultRunLoopMode];

Después de

myTimer = [NSTimer timerWithTimeInterval:0.01667 target:self selector:@selector(timerCallback) userInfo:nil repeats:YES];

Funcionó para mí (Como WolfLink recomendó que hiciera la subclase UIProgressView)

 3
Author: danihvilla,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-29 00:43:21

Si alguien quiere hacerlo en swift 3, pasé unos días tratando de averiguarlo y finalmente lo hice.

Aquí está el código:)

override func viewDidLoad() {
    super.viewDidLoad()

    let url = NSURL(string: "http://google.com")
    let request = NSURLRequest(url: url as! URL)
    webView.loadRequest(request as URLRequest)
    webView.delegate=self

}

func webViewDidStartLoad(_ webView: UIWebView) {

    self.progressView.setProgress(0.1, animated: false)
}


func webViewDidFinishLoad(_ webView: UIWebView) {

    self.progressView.setProgress(1.0, animated: true)
}

func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {

    self.progressView.setProgress(1.0, animated: true)
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}
 3
Author: Matej Marić,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-30 13:21:04

Es difícil (si es posible), ya que tendría que rastrear todos los recursos cargados por el sitio, pero {

Tengo una idea. Es más un truco que una solución real, pero creo que incluso Apple usa esto en la aplicación de mensajes:)
  1. Cuando comienzas a cargar la página, comienza una animación al 90% del progreso (digamos que con una duración de 1.5 segundos, tal vez sea diferente para Wi-Fi, LTE, 3G,)).
  2. Cuando la página se carga mientras tanto, progresa a 100% . Hecho!
  3. Si la página tarda más en cargarse, la barra de progreso se detendrá al 90% y esperará allí. Momento frustrante cuando el usuario mira indicador de giro lento en la barra de estado! Y finalmente, la página termina de cargar y (como en la viñeta 2.) se reproduce animación rápida al 100%. Hecho!

Creo que todos sabemos, que así es como funciona la aplicación de mensajes, ya que no creo que el envío de SMS se pueda rastrear con un progreso tan preciso:)

 2
Author: Tricertops,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-21 22:38:16

Habría agregado un comentario, en lugar de agregar una respuesta, ¡pero todavía no tengo suficiente reputación para comentar!

Hace solo un par de días hice casi exactamente la misma pregunta. En esa pregunta incluí la solución que se me ocurrió. Mi solución es más complicada que la de WolfLink, pero rastrea el progreso real de cargar la página, aunque no es 100% precisa. Como WolfLink ha dicho eso no es posible. Mi pregunta se puede encontrar aquí: Barra de progreso para UIWebView

Nota sea cual sea la forma en que lo hagas, tendrás que comprobar la propiedad loading de UIWebView para determinar cuándo se ha completado la carga de la página.

 0
Author: Stuart Fisher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:02:49

Apple ahora suministra el framework WebKit, que incluye la clase WKWebView que le permite consultar el progreso estimado usando la propiedad 'estimatedProgress', por lo que ya no debe 'falsificar' el progreso como lo hace para mostrar una barra de progreso en un UIWebView.

 0
Author: Patrick T Nelson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-26 15:17:52