Activity indicator with custom image

后端 未结 10 1272
甜味超标
甜味超标 2021-01-31 05:58

I am loading a UIWebView and in the meantime I wan\'t to show a blank page with this\"spinner\" activity indic

10条回答
  •  说谎
    说谎 (楼主)
    2021-01-31 06:42

    Swift 5

    Another answer working perfect

    Step 1.

    Create swift file "CustomLoader.swift" and put this code in that file

    import UIKit
    import CoreGraphics
    import QuartzCore
    
    class CustomLoader: UIView
    {
        //MARK:- NOT ACCESSABLE OUT SIDE
    
        fileprivate var duration : CFTimeInterval! = 1
        fileprivate var isAnimating :Bool = false
        fileprivate var backgroundView : UIView!
    
        //MARK:- ACCESS INSTANCE ONLY AND CHANGE ACCORDING TO YOUR NEEDS   *******
        let colors : [UIColor] = [.red,  .blue,  .orange, .purple]
        var defaultColor : UIColor = UIColor.red
        var isUsrInteractionEnable : Bool = false
        var defaultbgColor: UIColor = UIColor.white
        var loaderSize : CGFloat = 80.0
        /// **************** ******************  ////////// **************
    
        //MARK:- MAKE SHARED INSTANCE
        private static var Instance : CustomLoader!
        static let sharedInstance : CustomLoader = {
    
            if Instance == nil
            {
                Instance = CustomLoader()
            }
    
            return Instance
        }()
    
        //MARK:- DESTROY TO SHARED INSTANCE
        @objc fileprivate func destroyShardInstance()
        {
            CustomLoader.Instance = nil
        }
    
        //MARK:- SET YOUR LOADER INITIALIZER FRAME ELSE DEFAULT IS CENTER
        func startAnimation()
        {
            let win = UIApplication.shared.keyWindow
    
            backgroundView = UIView()
            backgroundView.frame = (UIApplication.shared.keyWindow?.frame)!
            backgroundView.backgroundColor = UIColor.init(white: 0, alpha: 0.4)
            win?.addSubview(backgroundView)
    
            self.frame = CGRect.init(x: ((UIScreen.main.bounds.width) - loaderSize)/2, y: ((UIScreen.main.bounds.height) - loaderSize)/2, width: loaderSize, height: loaderSize)
    
            self.addCenterImage()
            self.isHidden = false
            self.backgroundView.addSubview(self)
    
            self.layer.cornerRadius = loaderSize/2
            self.layer.masksToBounds = true
            backgroundView.accessibilityIdentifier = "CustomLoader"
    
            NotificationCenter.default.removeObserver(self, name: NSNotification.Name.NSExtensionHostDidBecomeActive, object: nil)
            NotificationCenter.default.addObserver(self, selector: #selector(CustomLoader.ResumeLoader), name: NSNotification.Name.NSExtensionHostDidBecomeActive, object: nil)
    
            self.layoutSubviews()
        }
    
        //MARK:- AVOID STUCKING LOADER WHEN CAME BACK FROM BACKGROUND
        @objc fileprivate func ResumeLoader()
        {
            if isAnimating
            {
                self.stopAnimation()
                self.AnimationStart()
            }
        }
    
        override func layoutSubviews()
        {
            super.layoutSubviews()
    
            self.backgroundColor = defaultbgColor
            UIApplication.shared.keyWindow?.isUserInteractionEnabled = isUsrInteractionEnable
            self.AnimationStart()
        }
    
        @objc fileprivate func addCenterImage()
        {
            /// add image in center
            let centerImage = UIImage(named: "Logo")
            let imageSize = loaderSize/2.5
    
            let centerImgView = UIImageView(image: centerImage)
            centerImgView.frame = CGRect(
                x: (self.bounds.width - imageSize) / 2 ,
                y: (self.bounds.height - imageSize) / 2,
                width: imageSize,
                height: imageSize
            )
    
            centerImgView.contentMode = .scaleAspectFit
            centerImgView.layer.cornerRadius = imageSize/2
            centerImgView.clipsToBounds = true
            self.addSubview(centerImgView)
    
        }
    
    
        //MARK:- CALL IT TO START THE LOADER , AFTER INITIALIZE THE LOADER
        @objc fileprivate func AnimationStart()
        {
            if isAnimating
            {
                return
            }
    
            let size = CGSize.init(width: loaderSize , height: loaderSize)
    
            let dotNum: CGFloat = 10
            let diameter: CGFloat = size.width / 5.5   //10
    
            let dot = CALayer()
            let frame = CGRect(
                x: (layer.bounds.width - diameter) / 2 + diameter * 2,
                y: (layer.bounds.height - diameter) / 2,
                width: diameter/1.3,
                height: diameter/1.3
            )
    
            dot.backgroundColor = colors[0].cgColor
            dot.cornerRadius = frame.width / 2
            dot.frame = frame
    
            let replicatorLayer = CAReplicatorLayer()
            replicatorLayer.frame = layer.bounds
            replicatorLayer.instanceCount = Int(dotNum)
            replicatorLayer.instanceDelay = 0.1
    
            let angle = (2.0 * M_PI) / Double(replicatorLayer.instanceCount)
    
            replicatorLayer.instanceTransform = CATransform3DMakeRotation(CGFloat(angle), 0.0, 0.0, 1.0)
    
            layer.addSublayer(replicatorLayer)
            replicatorLayer.addSublayer(dot)
    
            let scaleAnimation = CABasicAnimation(keyPath: "transform.scale")
            scaleAnimation.toValue = 0.4
            scaleAnimation.duration = 0.5
            scaleAnimation.autoreverses = true
            scaleAnimation.repeatCount = .infinity
            scaleAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
            dot.add(scaleAnimation, forKey: "scaleAnimation")
    
            let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation")
            rotationAnimation.toValue = -2.0 * Double.pi
            rotationAnimation.duration = 6.0
            rotationAnimation.repeatCount = .infinity
            rotationAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
            replicatorLayer.add(rotationAnimation, forKey: "rotationAnimation")
    
            if colors.count > 1 {
    
                var cgColors : [CGColor] = []
                for color in colors {
                    cgColors.append(color.cgColor)
                }
    
                let colorAnimation = CAKeyframeAnimation(keyPath: "backgroundColor")
                colorAnimation.values = cgColors
                colorAnimation.duration = 2
                colorAnimation.repeatCount = .infinity
                colorAnimation.autoreverses = true
                dot.add(colorAnimation, forKey: "colorAnimation")
    
            }
    
            self.isAnimating = true
            self.isHidden = false
    
        }
    
    
        //MARK:- CALL IT TO STOP THE LOADER
        func stopAnimation()
        {
            if !isAnimating
            {
                return
            }
            UIApplication.shared.keyWindow?.isUserInteractionEnabled = true
            let winSubviews = UIApplication.shared.keyWindow?.subviews
            if (winSubviews?.count)! > 0
            {
                for viw in winSubviews!
                {
                    if viw.accessibilityIdentifier == "CustomLoader"
                    {
                        viw.removeFromSuperview()
                        //  break
                    }
                }
            }
    
            layer.sublayers = nil
    
            isAnimating = false
            self.isHidden = true
    
            self.destroyShardInstance()
        }
        //MARK:- GETTING RANDOM COLOR , AND MANAGE YOUR OWN COLORS
        @objc fileprivate func randomColor()->UIColor
        {
            let randomRed:CGFloat = CGFloat(drand48())
            let randomGreen:CGFloat = CGFloat(drand48())
            let randomBlue:CGFloat = CGFloat(drand48())
            return UIColor(red: randomRed, green: randomGreen, blue: randomBlue, alpha: 1.0)
        }
        override func draw(_ rect: CGRect)
        {
        }
    }
    

    find the func name and "addCenterImage" and replace the image name with your custom image.

    Step 2

    Create the AppDelegate class instance out side of the AppDelegate class like this.

    var AppInstance: AppDelegate!
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate
    {    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
    {
        AppInstance = self
    }
    

    Step 3.

    put these two func in your AppDelegate

    //MARK: - Activity Indicator -
        func showLoader()
        {
            CustomLoader.sharedInstance.startAnimation()
        }
        func hideLoader()
        {
            CustomLoader.sharedInstance.stopAnimation()
        }
    

    Step 4. Use the functions like this whenever you want to animate your loader and stop.

    AppInstance.showLoader()
    AppInstance.hideLoader()
    

    HAPPY LOADING...

提交回复
热议问题