Skip to content

Instantly share code, notes, and snippets.

@JasonCanCode
Last active August 3, 2018 19:03
Show Gist options
  • Save JasonCanCode/1422ab11be1f7c6ae6765e3d7f102381 to your computer and use it in GitHub Desktop.
Save JasonCanCode/1422ab11be1f7c6ae6765e3d7f102381 to your computer and use it in GitHub Desktop.
Easily apply a loading overlay with interaction restrictions
import UIKit
/// Have a UIViewController adopt this to easily block interactions while loading.
protocol LoadingOverlayDisplayable: class {
var loadingOverlayView: LoadingOverlayView? { get set }
}
extension LoadingOverlayDisplayable where Self: UIViewController {
/// Call in `viewDidLoad` to establish the loading overlay view
func addLoadingOverlay() {
self.loadingOverlayView?.removeFromSuperview()
let loadingOverlayView = LoadingOverlayView(frame: view.frame)
view.addSubview(loadingOverlayView)
loadingOverlayView.translatesAutoresizingMaskIntoConstraints = false
loadingOverlayView.widthAnchor.constraint(equalTo: view.widthAnchor, constant: 0).isActive = true
loadingOverlayView.heightAnchor.constraint(equalTo: view.heightAnchor, constant: 0).isActive = true
loadingOverlayView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0).isActive = true
loadingOverlayView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0).isActive = true
self.loadingOverlayView = loadingOverlayView
}
/// Call when you want to show/hide the loading overlay
func updateLoadingSpinner(isLoading: Bool) {
DispatchQueue.main.async { [weak self] in
if isLoading {
self?.loadingOverlayView?.begin()
} else {
self?.loadingOverlayView?.end()
}
}
}
}
class LoadingOverlayView: UIView {
private var currentProcessesCount: UInt = 0 {
willSet {
isHidden = newValue == 0
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.configure()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.configure()
}
private func configure() {
isHidden = true
backgroundColor = UIColor.clear
let dimmerView = UIView(frame: frame)
dimmerView.backgroundColor = UIColor.black
dimmerView.alpha = 0.4
addSubview(dimmerView)
let indicator = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)
indicator.startAnimating()
addSubview(indicator)
dimmerView.translatesAutoresizingMaskIntoConstraints = false
dimmerView.widthAnchor.constraint(equalTo: self.widthAnchor, constant: 0).isActive = true
dimmerView.heightAnchor.constraint(equalTo: self.heightAnchor, constant: 0).isActive = true
dimmerView.centerXAnchor.constraint(equalTo: self.centerXAnchor, constant: 0).isActive = true
dimmerView.centerYAnchor.constraint(equalTo: self.centerYAnchor, constant: 0).isActive = true
indicator.translatesAutoresizingMaskIntoConstraints = false
indicator.centerXAnchor.constraint(equalTo: self.centerXAnchor, constant: 0).isActive = true
indicator.centerYAnchor.constraint(equalTo: self.centerYAnchor, constant: 0).isActive = true
}
func begin() {
if currentProcessesCount == 0 {
UIApplication.shared.beginIgnoringInteractionEvents()
}
currentProcessesCount += 1
}
func end() {
if currentProcessesCount > 0 {
currentProcessesCount -= 1
}
if currentProcessesCount == 0 {
UIApplication.shared.endIgnoringInteractionEvents()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment