Activity indicator with custom image Activity indicator with custom image ios ios

Activity indicator with custom image


Most of this is found in Stack Overflow. Let me summarize:

Create an UIImageView which will serve as an activity indicator (inside storyboard scene, NIB, code ... wherever you wish). Let's call it _activityIndicatorImage

Load your image: _activityIndicatorImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"activity_indicator"]];

You need to use animation to rotate it. Here is the method I use:

+ (void)rotateLayerInfinite:(CALayer *)layer{    CABasicAnimation *rotation;    rotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];    rotation.fromValue = [NSNumber numberWithFloat:0];    rotation.toValue = [NSNumber numberWithFloat:(2 * M_PI)];    rotation.duration = 0.7f; // Speed    rotation.repeatCount = HUGE_VALF; // Repeat forever. Can be a finite number.    [layer removeAllAnimations];    [layer addAnimation:rotation forKey:@"Spin"];}

Inside my layoutSubviews method I initiate rotation. You could place this in your webViewDidStartLoad and webViewDidFinishLoad if this is better for your case:

- (void)layoutSubviews{    [super layoutSubviews];    // some other code     [Utils rotateLayerInfinite:_activityIndicatorImage.layer];}

You could always always stop rotation using [_activityIndicatorImage.layer removeAllAnimations];


Swift 5

Another answer working perfect

Step 1.

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

import UIKitimport CoreGraphicsimport QuartzCoreclass 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!@UIApplicationMainclass 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...