带进度条的UIWebView

时间:2014-01-21 16:10:57

标签: ios uiwebview uiprogressview

您好我是编程的新手,我正在尝试在Xcode上制作我的第一个iPhone应用程序。 我的应用程序包含一个按钮,可在按下时打开UIWebView并加载主页。 现在我还想在Safari也使用的WebView中添加一个Progress View,它表示加载页面的进度。我怎么能这样做?
到目前为止,我的代码用于在UIWebView中加载URL:

·H

IBOutlet UIWebView *webView;

的.m

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

感谢您的帮助!

9 个答案:

答案 0 :(得分:70)

要获得准确的UIProgressView,您需要执行以下任务:

  • 您可以在信息不完整时获取信息
  • 根据该信息量化其“完整性”百分比。

现在当你加载UIWebView时,那是不可能的。苹果公司也没有做到这一点。 Apple经常使用假的UIProgressView来为您提供在页面加载时要查看的内容。 Mail还使用虚假进度视图。去试试吧。这就是Apple的虚假进展观点的工作方式:

  • 进度视图开始以缓慢,恒定的速度移动
  • 如果任务在栏完成之前完成,则在消失之前突然将其余部分拉到100%
  • 如果任务需要很长时间,则进度视图将停止在95%并保持在那里直到任务完成。

要实现此目的,您必须手动设置progressView的动画。你可以将它子类化,但这对你来说可能有点先进。最简单的方法是:

在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

在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

然后,在您的任务完成的位置,设置theBool = true;,进度视图将自行处理。更改if语句中的值以控制动画的速度。

答案 1 :(得分:5)

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

答案 2 :(得分:3)

我按照Wolflink的回答,发现同样的问题没有使用progressView动画。

阅读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

讨论中,您可以阅读: “您必须使用addTimer:forMode:”将新计时器添加到运行循环中。“

所以我添加了

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

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

它对我有用(正如WolfLink推荐的那样,我做了子类UIProgressView)

答案 3 :(得分:3)

如果有人想在swift 3中做到这一点,我花了几天时间试图找出它并最终做到了。

以下是代码:)

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

答案 4 :(得分:2)

很难(如果可能的话),因为您必须跟踪网站加载的所有资源,但是......

我有一个想法。它比真正的解决方案更像是一个技巧,但我认为即使Apple在消息应用程序中使用它:)

  1. 当你开始加载页面时,开始动画到90%的进度(假设持续时间为1.5秒,对于Wi-Fi,LTE,3G,......可能会有所不同)。
  2. 当页面同时加载时,会快速将进度设置为100%。完成!
  3. 如果页面需要更多时间加载,则进度条将停止在90%并将在那里等待。当用户在状态栏中观看慢速旋转指示器时的沮丧时刻!然后最后,页面加载完成(如在子弹2中),您将快速动画播放到100%。完成!
  4. 我想我们都知道,这就是消息应用程序的工作原理,因为我不相信能够以如此准确的进度跟踪发送短信:)

答案 5 :(得分:0)

我会添加评论,而不是添加答案,但我还没有足够的声誉来发表评论!

仅在几天前,我几乎问了同样的问题。在那个问题中,我提出了我想出的解决方案。我的解决方案比WolfLink更复杂,但它确实跟踪加载页面的真实进度,尽管它不是100%准确。正如WolfLink所说,这是不可能的。我的问题可以在这里找到:Progress bar for UIWebView

请注意,无论您采用哪种方式,都需要检查UIWebView的加载属性,以确定何时完成页面加载。

答案 6 :(得分:0)

Apple现在提供WebKit框架,其中包括WKWebView类,它允许您使用属性“估计进度”查询估计的进度,因此您不再需要假冒'像在UIWebView上显示进度条一样的进展。

答案 7 :(得分:0)

我尝试了以下模式。它给了我更好的结果。我正在使用WKWebview。

@IBOutlet weak var progressView: UIProgressView! // added in storyboard
@IBOutlet weak var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        setupEstimatedProgressObserver()
    }

    // Observe the WebViewClient for estimatedProgress value
    private func setupEstimatedProgressObserver() {
        estimatedProgressObserver = webView.observe(\.estimatedProgress, options: [.new]) { [weak self] webView, _ in
            self?.progressView.progress = Float(webView.estimatedProgress)
        }
    }

    //When WebView load finished in WKNavigationDelegate in didFinish method we will use the following approach
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        self.progressView.progress =  1.0
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
            // your code here
             self.progressView.isHidden = true
        }
    }

答案 8 :(得分:0)

这里的一些答案并不完全正确,因为它们忘记为Webview注册代表。不幸的是,实现UIWebViewDelegate并覆盖这两个方法是不够的。 您还必须将网络视图的委托设置为self

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.delegate = self // <--- important
        // ! 

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

此代码指的是答案@ ZAFAR007