How to add animated icon to OS X status bar?

Viewed 8434

I want to put an icon in Mac OS status bar as part of my cocoa application. What I do right now is:

NSStatusBar *bar = [NSStatusBar systemStatusBar];

sbItem = [bar statusItemWithLength:NSVariableStatusItemLength];
[sbItem retain];

[sbItem setImage:[NSImage imageNamed:@"Taski_bar_icon.png"]];
[sbItem setHighlightMode:YES];
[sbItem setAction:@selector(stopStart)];

but if I want the icon to be animated (3-4 frames), how do I do it?

3 Answers

Just had to do something similar recently in a simple project, so I'm posting my personal version written in Swift:

class StatusBarIconAnimationUtils: NSObject {
    private var currentFrame = 0
    private var animTimer : Timer
    private var statusBarItem: NSStatusItem!
    private var imageNamePattern: String!
    private var imageCount : Int!

    init(statusBarItem: NSStatusItem!, imageNamePattern: String, imageCount: Int) {
        self.animTimer = Timer.init()
        self.statusBarItem = statusBarItem
        self.imageNamePattern = imageNamePattern
        self.imageCount = imageCount
        super.init()
    }

    func startAnimating() {
        stopAnimating()
        currentFrame = 0
        animTimer = Timer.scheduledTimer(timeInterval: 5.0 / 30.0, target: self, selector: #selector(self.updateImage(_:)), userInfo: nil, repeats: true)
    }

    func stopAnimating() {
        animTimer.invalidate()
        setImage(frameCount: 0)
    }

    @objc private func updateImage(_ timer: Timer?) {
        setImage(frameCount: currentFrame)
        currentFrame += 1
        if currentFrame % imageCount == 0 {
            currentFrame = 0
        }
    }

    private func setImage(frameCount: Int) {
        let imagePath = "\(imageNamePattern!)\(frameCount)"
        print("Switching image to: \(imagePath)")
        let image = NSImage(named: NSImage.Name(imagePath))
        image?.isTemplate = true // best for dark mode
        DispatchQueue.main.async {
            self.statusBarItem.button?.image = image
        }
    }
}

Usage:

private let statusItem = 
    NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)

// Assuming we have a set of images with names: statusAnimatedIcon0, ..., statusAnimatedIcon6
private lazy var iconAnimation = 
    StatusBarIconAnimationUtils.init(statusBarItem: statusItem, imageNamePattern: "statusAnimatedIcon", 
    imageCount: 7)

private func startAnimation() {
    iconAnimation.startAnimating()
}

private func stopAnimating() {
    iconAnimation.stopAnimating()
}
Related