Подтвердить что ты не робот

UIWebView с панелью выполнения

Привет, я новичок в программировании, и я пытаюсь сделать свое первое приложение для iPhone на Xcode. Мое приложение содержит кнопку, открывающую UIWebView при нажатии и загрузку домашней страницы. Теперь я также хочу добавить представление Progress View в WebView, как и Safari, что указывает на прогресс загрузки страницы. Как я могу это сделать?
Мой код до сих пор загружает URL-адрес в UIWebView:

.h

IBOutlet UIWebView *webView;

ого

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

Спасибо за вашу помощь!

4b9b3361

Ответ 1

Чтобы иметь точный UIProgressView, вам нужно выполнить некоторую задачу:

  • Вы можете получить информацию, пока она не завершена.
  • Определите свою "полноту" в процентах на основе этой информации.

Теперь, когда вы загружаете UIWebView, это невозможно. И Apple тоже этого не делает. Apple часто использует поддельную UIProgressView, чтобы дать вам что-то посмотреть, пока загружается страница. Почта также использует поддельные представления прогресса. Попробуйте сами. Вот как работают поддельные представления прогресса 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, чтобы контролировать скорость анимации.

Ответ 2

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

Ответ 3

Если кто-то хочет сделать это в быстрой 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

Я последовал за ответом 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)

Ответ 5

Это сложно (если возможно), так как вам придется отслеживать все ресурсы, загруженные сайтом, но...

У меня есть одна идея. Это больше трюк, чем реальное решение, но я думаю, что даже Apple использует это в приложении Messages:)

  • Когда вы начнете загружать страницу, начните анимацию до 90% прогресса (скажем, продолжительностью 1,5 секунды, возможно, будет отличаться для Wi-Fi, LTE, 3G,...).
  • Когда страница загружается, быстро оживляет ход до 100%. Готово!
  • Если на страницу требуется больше времени для загрузки, индикатор выполнения остановится на 90% и будет ждать там. Разочарование момента, когда пользователь наблюдает за индикатором медленного вращения в строке состояния! И затем, наконец, загрузка страницы заканчивается и (как в марке 2.) вы играете быструю анимацию до 100%. Готово!

Я думаю, мы все знаем, что так работает приложение "Сообщения", так как я не верю, что отправка SMS может отслеживаться с таким точным прогрессом:)

Ответ 6

Apple теперь предоставляет платформу WebKit, которая включает в себя класс WKWebView, который позволяет запрашивать оценку прогресса, используя свойство "ProcProgress ", поэтому вам больше не нужно" подделывать "прогресс, как вы делаете, чтобы отображать индикатор выполнения в UIWebView.

Ответ 7

Я бы добавил комментарий вместо добавления ответа, но у меня пока нет достаточной репутации для комментариев!

Только пару дней назад я задал почти такой же вопрос. В этом вопросе я включил решение, которое я придумал. Мое решение сложнее, чем WolfLink, но оно отслеживает реальный ход загрузки страницы, хотя это не на 100% точно. Как сказал WolfLink, это невозможно. Мой вопрос можно найти здесь: Индикатор выполнения для UIWebView

Обратите внимание, какой бы способ вы это ни делал, вам нужно проверить свойство загрузки UIWebView, чтобы определить, когда будет завершена загрузка страницы.

Ответ 8

Я попробовал следующий шаблон. Это дало мне немного лучший результат. Я использую 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
        }
    }