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/"]]];
Спасибо за вашу помощь!
Ответы
Ответ 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
}
}