Using UIActivityIndicatorView with UIWebView in Swift
Asked Answered
C

7

13

I'm trying to display an Activity Indicator View in my app to users while a url is being loaded into a WebView. I've tried toying with activity.startAnimating/activity.stopAnimating and tried placing them in functions, etc. but have not had any luck.

The best I have been able to get is the Activity Indicator to appear and animate, but then not stop animating or hide once my url is loaded, so it continues spinning on top of the web page.

In other situations, when trying to move around activity.startAnimating, I have encountered the "Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)" issue. I have "Hides when Stopped" checked in the attributes inspector, I know that my url is valid, and I have created IBOutlets for the Interface Builder Elements.

Bear with me; I'm relatively new to Swift. Here's my code:

class HighchartsController: UIViewController {

@IBOutlet weak var HighchartsView: UIWebView!

@IBOutlet weak var activity: UIActivityIndicatorView!

@IBOutlet weak var saveButton: UIBarButtonItem!

@IBOutlet weak var highchartsMenu: UIBarButtonItem!

override func viewDidLoad()
{
    super.viewDidLoad()

    if self.revealViewController() != nil {
        highchartsMenu.target = self.revealViewController()
        highchartsMenu.action = "revealToggle:"

        loadAddress()
    }
 }

func loadAddress() {

    let url = NSURL (string: "http://google.com/flights")
    let request = NSURLRequest (URL: url!)
    HighchartsView.loadRequest(request)
    println("Webpage Loaded Successfully")
 }
}

And I have tried using different functions such as

webViewDidStartLoad(_ :UIWebView){

    activity.startAnimating()
    NSLog("Webview load has started")

}
webViewDidFinishLoad(_ :UIWebView){

    activity.stopAnimating()
    NSLog("Webview load had finished")

}
Curagh answered 1/4, 2015 at 22:9 Comment(0)
E
28

First of all, i don't see delegation of UIWebView. Realize your behaviour related to delegation processes.

UIWebViewDelegate has four methods, but use for this way just three:

Swift 4

func webViewDidStartLoad(_ webView: UIWebView) // show indicator    
func webViewDidFinishLoad(_ webView: UIWebView) // hide indicator
func webView(_ webView: UIWebView, didFailLoadWithError error: Error) // hide indicator

Swift 3

func webViewDidStartLoad(webView: UIWebView!) // show indicator
func webViewDidFinishLoad(webView: UIWebView!) // hide indicator
func webView(webView: UIWebView!, didFailLoadWithError error: NSError!) // hide indicator
Emanation answered 1/4, 2015 at 22:50 Comment(2)
outside of adding UIWebViewDelegate after 'class HighchartsController: UIViewController' and adding in 'highchartsView.delegate = self', how do I delegate UIWebview? Sorry, I'm new to Swift and Xcode.Curagh
@Curagh you need to delegate UIWebview's protocol UIWebViewDelegate to your class, and implement inside described functions in subscribed protocol – UIWebViewDelegate.Emanation
S
10

*WKWebView equivalent of dimpiax answer. Use WKNavigationDelegate

func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) // show indicator 

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)  // hide indicator 

func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error)  // hide indicator*  
Statuary answered 6/4, 2018 at 8:9 Comment(1)
UIWebView is now deprecated, and we have to use WKWebView, this code is now the solution. but don't forget to add webView.navigationDelegate = self at viewDidLoad . Thanks ParionForecourse
L
4

You need to add UIWebViewDelegate to your class like so.

class HighchartsController: UIViewController, UIWebViewDelegate {

You will also need to assign your webView delegate to self in viewDidLoad function like so.

HighchartsView.delegate = self
Liberalize answered 19/11, 2016 at 16:40 Comment(2)
Instead of UIWEBViewDelegate it should be UIWebViewDelegateCambric
Small oversight. Thanks.Liberalize
I
3

I'm sure you figured it out by now but you need to wire up your UIWebView to set its delegate as your UIViewController in the storyboard by control-dragging.

Immeasurable answered 15/2, 2016 at 14:24 Comment(0)
B
3

The following are three simple steps that I always follow in Xcode 8 / Swift 3 / iOS 10 in order to implement UIWebView page loading indicator:

Step 1. Create outlets for the Web View and Load Indicator in the ViewController class. For example:

@IBOutlet var loadSpinner: UIActivityIndicatorView!
@IBOutlet weak var webView: UIWebView!

These two lines should have non-empty dots to the left of them.

Step 2. In the Storyboard: Control-drag the WebView to the ViewController and choose "delegate" from the menu. As GarySabo correctly pointed out, without this step, the indicator will appear but won't work!

Step 3. Add the following code to your ViewController class:

func webViewDidStartLoad(_ : UIWebView) {
    loadSpinner.startAnimating()
}

func webViewDidFinishLoad(_ : UIWebView) {
    loadSpinner.stopAnimating()
}
Bork answered 6/8, 2017 at 18:59 Comment(0)
B
3

If you are using WKWebView, set WKNavigationDelegate like

webView.navigationDelegate = self

func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
    //Show loader
}    
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    //Hide loader
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
    //Hide loader
}
Bestiality answered 19/3, 2020 at 15:24 Comment(0)
H
1
extension WebViewController: WKNavigationDelegate {
    
    func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
        print("Start loading")
        LoadingIndicator.show()
    }
    
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        print("End loading")
        LoadingIndicator.hide()
    }
}

Call the delegate methods. It's working fine.

Hymnal answered 29/10, 2020 at 8:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.