Loading an “overlay” when running long tasks in iOS

前端 未结 11 903
没有蜡笔的小新
没有蜡笔的小新 2020-12-22 16:15

What is example for loading overlay in Swift IOS application when do a long tasks. Example for loading data from remote server. I googled but not found any answer.

U

相关标签:
11条回答
  • 2020-12-22 16:52

    Swift 5

    class func showUniversalLoadingView(_ show: Bool, loadingText : String = "") {
        let existingView = UIApplication.shared.windows[0].viewWithTag(1200)
        if show {
            if existingView != nil {
                return
            }
            let loadingView = self.makeLoadingView(withFrame: UIScreen.main.bounds, loadingText: loadingText)
            loadingView?.tag = 1200
            UIApplication.shared.windows[0].addSubview(loadingView!)
        } else {
            existingView?.removeFromSuperview()
        }
    
    }
    
    
    
     class func makeLoadingView(withFrame frame: CGRect, loadingText text: String?) -> UIView? {
        let loadingView = UIView(frame: frame)
        loadingView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5)
        let activityIndicator = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        //activityIndicator.backgroundColor = UIColor(red:0.16, green:0.17, blue:0.21, alpha:1)
        activityIndicator.layer.cornerRadius = 6
        activityIndicator.center = loadingView.center
        activityIndicator.hidesWhenStopped = true
        activityIndicator.style = .white
        activityIndicator.startAnimating()
        activityIndicator.tag = 100 // 100 for example
    
        loadingView.addSubview(activityIndicator)
        if !text!.isEmpty {
            let lbl = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 30))
            let cpoint = CGPoint(x: activityIndicator.frame.origin.x + activityIndicator.frame.size.width / 2, y: activityIndicator.frame.origin.y + 80)
            lbl.center = cpoint
            lbl.textColor = UIColor.white
            lbl.textAlignment = .center
            lbl.text = text
            lbl.tag = 1234
            loadingView.addSubview(lbl)
        }
        return loadingView
    }
    

    Uses

    showUniversalLoadingView(true, loadingText: "Downloading Data.......")
    

    showUniversalLoadingView(true)

    Remove loader

    showUniversalLoadingView(false)
    
    0 讨论(0)
  • 2020-12-22 16:53

    To add on to the answers given, you might run into issues if you are attempting to run the code sometimes. Personally, there was an occasion where showOverlay was not being properly called (because I was trying to segue into a scene, then immediately call this function during viewDidLoad).

    If you run into an issue similar to mine, there is one fix to the code and a change in approach I recommend.

    FIX: Place both blocks of code as closures to a dispatch_async call, like so:

    dispatch_async(dispatch_get_main_queue(),
     { //code });
    

    APPROACH: When calling your code, do a dispatch_after call onto the main queue to delay the call by a few milliseconds.

    The reasoning? You're simply asking the UI to do too much during viewDidLoad.

    If this appendix to the solution helped, I'd be glad.

    -Joel Long

    P.S. Solution worked for XCode v6.3.2

    0 讨论(0)
  • 2020-12-22 16:53

    Updated @sonrobby answer, added a background view and orientation handling via resizing mask... this can be used for simple stuffs

    public class LoadingOverlay{
    
        var overlayView = UIView()
        var activityIndicator = UIActivityIndicatorView()
        var bgView = UIView()
    
        class var shared: LoadingOverlay {
            struct Static {
                static let instance: LoadingOverlay = LoadingOverlay()
            }
            return Static.instance
        }
    
        public func showOverlay(view: UIView) {
    
            bgView.frame = view.frame
            bgView.backgroundColor = UIColor.gray
            bgView.addSubview(overlayView)
            bgView.autoresizingMask = [.flexibleLeftMargin,.flexibleTopMargin,.flexibleRightMargin,.flexibleBottomMargin,.flexibleHeight, .flexibleWidth]
            overlayView.frame = CGRect(x: 0, y: 0, width: 80, height: 80)
            overlayView.center = view.center
            overlayView.autoresizingMask = [.flexibleLeftMargin,.flexibleTopMargin,.flexibleRightMargin,.flexibleBottomMargin]
            overlayView.backgroundColor = UIColor.black
            overlayView.clipsToBounds = true
            overlayView.layer.cornerRadius = 10
    
            activityIndicator.frame = CGRect(x: 0, y: 0, width: 40, height: 40)
            activityIndicator.activityIndicatorViewStyle = .whiteLarge
            activityIndicator.center = CGPoint(x: overlayView.bounds.width / 2, y: overlayView.bounds.height / 2)
    
            overlayView.addSubview(activityIndicator)
            view.addSubview(bgView)
            self.activityIndicator.startAnimating()
    
        }
    
        public func hideOverlayView() {
            activityIndicator.stopAnimating()
            bgView.removeFromSuperview()
        }
    }
    

    if you add it to keywindow, it can then go over your nav and tab bars also... something like this

    LoadingOverlay.shared.showOverlay(view: UIApplication.shared.keyWindow!)
    
    0 讨论(0)
  • 2020-12-22 16:55

    @Ajinkya Patil answer as a reference. Swift 4.0 and newer

    This is an Extension Solution to use on all viewController without clashing.

    Create a LoadingDialog+ViewContoller.swift

    import UIKit
    
    struct ProgressDialog {
        static var alert = UIAlertController()
        static var progressView = UIProgressView()
        static var progressPoint : Float = 0{
            didSet{
                if(progressPoint == 1){
                    ProgressDialog.alert.dismiss(animated: true, completion: nil)
                }
            }
        }
    }
    extension UIViewController{
       func LoadingStart(){
            ProgressDialog.alert = UIAlertController(title: nil, message: "Please wait...", preferredStyle: .alert)
        
        let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
        loadingIndicator.hidesWhenStopped = true
        loadingIndicator.style = UIActivityIndicatorView.Style.gray
        loadingIndicator.startAnimating();
    
        ProgressDialog.alert.view.addSubview(loadingIndicator)
        present(ProgressDialog.alert, animated: true, completion: nil)
      }
    
      func LoadingStop(){
        ProgressDialog.alert.dismiss(animated: true, completion: nil)
      }
    }
    

    call the function inside ViewController anywhere you like. like so:

    self.LoadingStart()
    

    and here's how to stop the loading dialog.

    self.LoadingStop()
    
    0 讨论(0)
  • 2020-12-22 16:56

    Blur background + Activity Indicator, Swift 5 example

    extension UIView {
        func showBlurLoader() {
            let blurLoader = BlurLoader(frame: frame)
            self.addSubview(blurLoader)
        }
    
        func removeBluerLoader() {
            if let blurLoader = subviews.first(where: { $0 is BlurLoader }) {
                blurLoader.removeFromSuperview()
            }
        }
    }
    
    
    class BlurLoader: UIView {
    
        var blurEffectView: UIVisualEffectView?
    
        override init(frame: CGRect) {
            let blurEffect = UIBlurEffect(style: .dark)
            let blurEffectView = UIVisualEffectView(effect: blurEffect)
            blurEffectView.frame = frame
            blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
            self.blurEffectView = blurEffectView
            super.init(frame: frame)
            addSubview(blurEffectView)
            addLoader()
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        private func addLoader() {
            guard let blurEffectView = blurEffectView else { return }
            let activityIndicator = UIActivityIndicatorView(style: .whiteLarge)
            activityIndicator.frame = CGRect(x: 0, y: 0, width: 50, height: 50)
            blurEffectView.contentView.addSubview(activityIndicator)
            activityIndicator.center = blurEffectView.contentView.center
            activityIndicator.startAnimating()
        }
    }
    

    0 讨论(0)
  • 2020-12-22 16:57

    Just create yourself an overlay view, which you add to your parent view and remove it once your task is done, e.g. to add it:

    var overlay : UIView? // This should be a class variable
    
    [ ... ]
    
    overlay = UIView(frame: view.frame)
    overlay!.backgroundColor = UIColor.blackColor()
    overlay!.alpha = 0.8
    
    view.addSubview(overlay!)
    

    For removal:

    overlay?.removeFromSuperview()
    
    0 讨论(0)
提交回复
热议问题