Skip to content

5. Alerts With Progress Bar

Gabriel Theodoropoulos edited this page Apr 17, 2019 · 1 revision

Alerts with progress bar

An alert with a progress bar is good for showing a process being in progress, but this time the length of the process is known beforehand. Here's how we can present such an alert:

GTAlertCollection.shared.presentProgressBarAlert(withTitle: "Upload", message: "Your files are being uploaded...", progressTintColor: .red, trackTintColor: .lightGray, showPercentage: true, showStepsCount: false, updateHandler: { (updateHandler) in
    // Update the progress here...    
}) { (success) in
    if success {
       // Do something after the alert has been presented..
    }
}

There are a few things to discuss here, so let's start with the new parameters being available:

  • progresstTintColor: It's the tint color of the progress bar (the graphical part moving and showing the progress).
  • trackTintColor: It's the tint color of the track (the graphical part that looks "empty" and gets filled by the progress bar gradually).
  • showPercentage: When it's true, a percentage of the overall process is being displayed right below the progress bar. Set the showStepsCount to false to use it.
  • showStepsCount: When it's true, a message similar to "5 / 50" is displayed right below the progress bar, indicating the current step of the entire process, as well the total steps required until the process gets completed. To use it, switch the showPercentage to false.

If you don't want any textual message below the progress bar, pass false for both showPercentage and showStepsCount arguments.

There are also two handler blocks. The second one used to determine if the alert was presented successfully to the host view controller, and once again we have the success parameter that shows that. But the most interesting is the first one, where we can update the progress.

There's a parameter called updateHandler in the first handler closure, which must be called just like that when we want to update the progress:

updateHandler(currentStep, totalSteps)

It expects two arguments, where the first one indicates the current step in the overall process, and the second the total steps required to be done until the process gets finished.

There are two ways to use the updateHandler. First, inside the closure where we apply all the required logic by the app, and we update the progress as well. The following example demonstrates that:

GTAlertCollection.shared.presentProgressBarAlert(withTitle: "Upload", message: "Your files are being uploaded...", progressTintColor: .red, trackTintColor: .lightGray, showPercentage: true, showStepsCount: false, updateHandler: { (updateHandler) in

    let totalSteps = 50
    var currentStep = 0

    Timer.scheduledTimer(withTimeInterval: 0.05, repeats: true, block: { (timer) in
        currentStep += 1

        updateHandler(currentStep, totalSteps)

        if currentStep == totalSteps {
            timer.invalidate()

            GTAlertCollection.shared.dismissAlert(completion: nil)
        }

    })

}) { (success) in
    if success {

    }
}

The code above will keep updating the progress every 0.05 seconds, until the currentStep reaches the totalSteps value. At the end, it dismisses the alert. See the usage of the updateHandler that makes it possible to update the progress visually.

The second way, and most probably the most usual case, is to use the updateHandler out of the closure body. The above example works fine, but it's just a demo. In most cases, you'll want to start updating the process once you know that the alert has been presented, and of course after the real work that leads to the progress updating has started. To cover that scenario, first of all you need a property in your class where you'll keep the updateHandler parameter so you can access it later:

// Declare this as a class property.
var updateHandler: ((_ currentItem: Int, _ totalItems: Int) -> Void)!

Next, in the first closure of the above method assign the updateHandler to the property we just declared. At the same time, in the second closure start doing the real work once the alert has been presented. Let's see the method updated as described here:

GTAlertCollection.shared.presentProgressBarAlert(withTitle: "Upload", message: "Your files are being uploaded...", progressTintColor: .red, trackTintColor: .lightGray, showPercentage: true, showStepsCount: false, updateHandler: { (updateHandler) in

    self.updateHandler = updateHandler

}) { (success) in
    if success {
        self.updateProgress()
    }
}

For our demonstration, the real work for us is taking place in the updateProgress() method, which simply updates the progress:

func updateProgress() {
    let totalSteps = 50
    var currentStep = 0
    Timer.scheduledTimer(withTimeInterval: 0.05, repeats: true, block: { (timer) in
        currentStep += 1

        if let updateHandler = self.updateHandler {
            updateHandler(currentStep, totalSteps)
        }

        if currentStep == totalSteps {
            timer.invalidate()

            GTAlertCollection.shared.dismissAlert(completion: nil)
        }

    })
}

That snippet is similar to the previous one that updates the progress visually. Even though it's a simple example, all steps presented here is your guide for real-life projects too.

Progress bar alert