Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift - best way to show alert with loading indicator right away after button is clicked?

Tags:

ios

swift

I tried using the main thread to show but it didn't work, any thought why the alert doesn't show up right away?

@IBAction func updateData(_ sender: Any) {
    let alert = UIAlertController(title: "Updating data", message: "Please wait...", preferredStyle: .alert)
    alert.view.tintColor = UIColor.black
    let loadingIndicator: UIActivityIndicatorView = UIActivityIndicatorView(frame: CGRect(x: 10,y: 5,width: 50, height: 50)) as UIActivityIndicatorView
    loadingIndicator.hidesWhenStopped = true
    loadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
    loadingIndicator.startAnimating();

    alert.view.addSubview(loadingIndicator)
    DispatchQueue.main.async {
        self.present(alert, animated: true)

    }
like image 643
QTB Avatar asked Jan 16 '26 22:01

QTB


2 Answers

UIAlertController can not be customized, so for me the best solution was to create a custom UIView XIB and then instatiate it on the ViewController I need.

The XIB View could be like this: XIB View

then you create a CustomAlertLoadingView.swift file which subclass UIView, associate it to the XIB and create the IBOutlets.

To show it in any ViewController just create this extension

extension UIViewController {
     func presentAlert(title: String) {
        let nib = UINib(nibName: "CustomAlertLoadingView", bundle: nil)
        let customAlert = nib.instantiate(withOwner: self, options: nil).first as! CustomAlertLoadingView

        customAlert.tag = 12345
        customAlert.titleAlertLabel.text = title
        customAlert.indicator.startAnimating()


        let screen = UIScreen.main.bounds
        customAlert.center = CGPoint(x: screen.midX, y: screen.midY)

        self.view.addSubview(customAlert)
    }
}

use self.yourViewController.presentAlert(title:"yourTitle")

To dismiss the alert, create this function inside the UIVIewController extension

func dismissCustomAlert() {
        if let view = self.view.viewWithTag(12345) {
            view.removeFromSuperview()
        }
}

then call self.yourViewController.dismissCustomAlert

like image 102
Santiago Carmona González Avatar answered Jan 19 '26 11:01

Santiago Carmona González


I ran this through Xcode without any delay:

@IBAction func updateData(_ sender: UIButton) {
    print("button fire")
    let alert = UIAlertController(title: "Updating data", message: "Please wait...", preferredStyle: .alert)
    alert.view.tintColor = UIColor.black
    let loadingIndicator: UIActivityIndicatorView = UIActivityIndicatorView(frame: CGRect(x: 10,y: 5,width: 50, height: 50)) as UIActivityIndicatorView
    loadingIndicator.hidesWhenStopped = true
    loadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
    loadingIndicator.startAnimating();

    alert.view.addSubview(loadingIndicator)
    self.present(alert, animated: true)

}

I replaced the sender parameter of your function with a UIButton and took out the Dispatch call to the main queue since it's unnecessary. No delays at all!

When you say that there is a delay do you mean only when you step trough the code? Because yes if you're stepping through it, the alert view won't be displayed right after self.present(alert, animated: true). You'll have to wait until the function completes execution. But that "delay" isn't visible to the human eye. Did you trying running the above code without stepping through it?

like image 44
alexisSchreier Avatar answered Jan 19 '26 10:01

alexisSchreier



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!