Skip to content

Instantly share code, notes, and snippets.

@edc0der
Last active December 17, 2023 13:37
Show Gist options
  • Save edc0der/e4bed05b4c6653ffcd36c0609f27c7c6 to your computer and use it in GitHub Desktop.
Save edc0der/e4bed05b4c6653ffcd36c0609f27c7c6 to your computer and use it in GitHub Desktop.
iOS + Swift: Display activity indicator overlay - UIViewController extension
import UIKit
fileprivate let overlayViewTag: Int = 999
fileprivate let activityIndicatorViewTag: Int = 1000
// Public interface
extension UIView {
func displayAnimatedActivityIndicatorView() {
setActivityIndicatorView()
}
func hideAnimatedActivityIndicatorView() {
removeActivityIndicatorView()
}
}
extension UIViewController {
private var overlayContainerView: UIView {
if let navigationView: UIView = navigationController?.view {
return navigationView
}
return view
}
func displayAnimatedActivityIndicatorView() {
overlayContainerView.displayAnimatedActivityIndicatorView()
}
func hideAnimatedActivityIndicatorView() {
overlayContainerView.hideAnimatedActivityIndicatorView()
}
}
// Private interface
extension UIView {
private var activityIndicatorView: UIActivityIndicatorView {
let view: UIActivityIndicatorView = UIActivityIndicatorView(style: .large)
view.translatesAutoresizingMaskIntoConstraints = false
view.tag = activityIndicatorViewTag
return view
}
private var overlayView: UIView {
let view: UIView = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .black
view.alpha = 0.5
view.tag = overlayViewTag
return view
}
private func setActivityIndicatorView() {
guard !isDisplayingActivityIndicatorOverlay() else { return }
let overlayView: UIView = self.overlayView
let activityIndicatorView: UIActivityIndicatorView = self.activityIndicatorView
//add subviews
overlayView.addSubview(activityIndicatorView)
addSubview(overlayView)
//add overlay constraints
overlayView.heightAnchor.constraint(equalTo: heightAnchor).isActive = true
overlayView.widthAnchor.constraint(equalTo: widthAnchor).isActive = true
//add indicator constraints
activityIndicatorView.centerXAnchor.constraint(equalTo: overlayView.centerXAnchor).isActive = true
activityIndicatorView.centerYAnchor.constraint(equalTo: overlayView.centerYAnchor).isActive = true
//animate indicator
activityIndicatorView.startAnimating()
}
private func removeActivityIndicatorView() {
guard let overlayView: UIView = getOverlayView(), let activityIndicator: UIActivityIndicatorView = getActivityIndicatorView() else {
return
}
UIView.animate(withDuration: 0.2, animations: {
overlayView.alpha = 0.0
activityIndicator.stopAnimating()
}) { _ in
activityIndicator.removeFromSuperview()
overlayView.removeFromSuperview()
}
}
private func isDisplayingActivityIndicatorOverlay() -> Bool {
getActivityIndicatorView() != nil && getOverlayView() != nil
}
private func getActivityIndicatorView() -> UIActivityIndicatorView? {
viewWithTag(activityIndicatorViewTag) as? UIActivityIndicatorView
}
private func getOverlayView() -> UIView? {
viewWithTag(overlayViewTag)
}
}
@edc0der
Copy link
Author

edc0der commented May 29, 2020

Updated the snippet with @acamill's suggested code. Thank you!

Changes:

  • Added type annotation
  • Separated the display method into display and hide, in order to have single responsibility methods
  • Added UIViewController extension to use the overlay to cover the fullscreen without having to write navigationController?.view.displayAnimatedActivityIndicatorView()

@acamill
Copy link

acamill commented May 30, 2020 via email

@wiles88
Copy link

wiles88 commented Jun 28, 2020

How is this applied to a normal swiftUI page. If I want the page to display the loading icon how do I do that?

Import SwiftUI

struct Welcome: View {
  
    var body: some View {
<< DISPLAY LOADING HERE >>
        Text("Hello World")
    }
}

struct Dashboard_Previews: PreviewProvider {
    static var previews: some View {
        Welcome()
    }
    
}

@ahmdmau
Copy link

ahmdmau commented Aug 6, 2020

Thanks for sharing!

@acamill
Copy link

acamill commented Aug 6, 2020 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment