This post shows how to implement a LoadingViewController and fade-in the LoadingViewController to show the app is performing some activity, like a network request.

Create A Loading View Controller

The first step is to subclass UIViewController and add a few placeholders. LoadingViewController will be implemented with a UIActivityIndicatorView to help inform the user progress is occurring, and a UIVisualEffectView to create a darkened blur.

class LoadingViewController: UIViewController {
    var loadingActivityIndicator: UIActivityIndicatorView = {
        // UIActivityIndicatorView Configuration
    }()
    
    var blurEffectView: UIVisualEffectView = {
        // UIVisualEffectView Configuration
    }()
    
    override func viewDidLoad() {
        // View Configuration
    }
}

Add A White Spinner

For this LoadingViewController, a large, white, and animating UIActivityIndicatorView will be used.

var loadingActivityIndicator: UIActivityIndicatorView = {
    let indicator = UIActivityIndicatorView()
    
    indicator.style = .large
    indicator.color = .white
        
    // The indicator should be animating when
    // the view appears.
    indicator.startAnimating()
        
    // Setting the autoresizing mask to flexible for all
    // directions will keep the indicator in the center
    // of the view and properly handle rotation.
    indicator.autoresizingMask = [
        .flexibleLeftMargin, .flexibleRightMargin,
        .flexibleTopMargin, .flexibleBottomMargin
    ]
        
    return indicator
}()

Add A Dark, Blurred Background

For this LoadingViewController, the UIVisualEffectView will be dark and partially transparent.

var blurEffectView: UIVisualEffectView = {
    let blurEffect = UIBlurEffect(style: .dark)
    let blurEffectView = UIVisualEffectView(effect: blurEffect)
    
    blurEffectView.alpha = 0.8
    
    // Setting the autoresizing mask to flexible for
    // width and height will ensure the blurEffectView
    // is the same size as its parent view.
    blurEffectView.autoresizingMask = [
        .flexibleWidth, .flexibleHeight
    ]
    
    return blurEffectView
}()

Override ViewDidLoad

To tie the components of LoadingViewController together, override viewDidLoad.

override func viewDidLoad() {
    super.viewDidLoad()
    
    view.backgroundColor = UIColor.black.withAlphaComponent(0.5)
    
    // Add the blurEffectView with the same
    // size as view
    blurEffectView.frame = self.view.bounds
    view.insertSubview(blurEffectView, at: 0)
    
    // Add the loadingActivityIndicator in the
    // center of view
    loadingActivityIndicator.center = CGPoint(
        x: view.bounds.midX,
        y: view.bounds.midY
    )
    view.addSubview(loadingActivityIndicator)
}

Loading View Controller With Fade In Animation

That’s it! To display LoadingViewController, use the following:

let loadingVC = LoadingViewController()

// Animate loadingVC over the existing views on screen
loadingVC.modalPresentationStyle = .overCurrentContext

// Animate loadingVC with a fade in animation
loadingVC.modalTransitionStyle = .crossDissolve
       
present(loadingVC, animated: true, completion: nil)

The result is an animating activity indicator and darkened screen blur that can be used to inform a user that progress is occurring:

iOS Loading Overlay With Activity Indicator And Fade-In Animation Example In Swift
iOS Loading Overlay With Activity Indicator And Fade-In Animation Example In Swift