Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Cocoa 如何将动画图标添加到OSX状态栏?_Cocoa_Macos_Statusbar - Fatal编程技术网

Cocoa 如何将动画图标添加到OSX状态栏?

Cocoa 如何将动画图标添加到OSX状态栏?,cocoa,macos,statusbar,Cocoa,Macos,Statusbar,我想在Mac OS状态栏中放置一个图标,作为cocoa应用程序的一部分。我现在做的是: NSStatusBar *bar = [NSStatusBar systemStatusBar]; sbItem = [bar statusItemWithLength:NSVariableStatusItemLength]; [sbItem retain]; [sbItem setImage:[NSImage imageNamed:@"Taski_bar_icon.png"]]; [sbItem set

我想在Mac OS状态栏中放置一个图标,作为cocoa应用程序的一部分。我现在做的是:

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)];

但是如果我想让图标动画化(3-4帧),我该怎么做

您需要在
NSStatusItem
上反复调用
-setImage:
,每次传入不同的图像。最简单的方法是使用
NSTimer
和实例变量来存储动画的当前帧

大概是这样的:

/*

assume these instance variables are defined:

NSInteger currentFrame;
NSTimer* animTimer;

*/

- (void)startAnimating
{
    currentFrame = 0;
    animTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/30.0 target:self selector:@selector(updateImage:) userInfo:nil repeats:YES];
}

- (void)stopAnimating
{
    [animTimer invalidate];
}

- (void)updateImage:(NSTimer*)timer
{
    //get the image for the current frame
    NSImage* image = [NSImage imageNamed:[NSString stringWithFormat:@"image%d",currentFrame]];
    [statusBarItem setImage:image];
    currentFrame++;
    if (currentFrame % 4 == 0) {
        currentFrame = 0;
    }
}

我重新编写了Rob的解决方案,以便可以重复使用:

我有第9帧,所有的图像名称都有最后一个数字作为帧编号,这样我每次都可以重置图像来设置图标的动画

//IntervalAnimator.h

    #import <Foundation/Foundation.h>

@protocol IntervalAnimatorDelegate <NSObject>

- (void)onUpdate;

@end


@interface IntervalAnimator : NSObject
{
    NSInteger numberOfFrames;
    NSInteger currentFrame;
    __unsafe_unretained id <IntervalAnimatorDelegate> delegate;
}

@property(assign) id <IntervalAnimatorDelegate> delegate;
@property (nonatomic) NSInteger numberOfFrames;
@property (nonatomic) NSInteger currentFrame;

- (void)startAnimating;
- (void)stopAnimating;
@end

#import "IntervalAnimator.h"

@interface IntervalAnimator()
{
    NSTimer* animTimer;
}

@end

@implementation IntervalAnimator
@synthesize numberOfFrames;
@synthesize delegate;
@synthesize currentFrame;

- (void)startAnimating
{
    currentFrame = -1;
    animTimer = [NSTimer scheduledTimerWithTimeInterval:0.50 target:delegate selector:@selector(onUpdate) userInfo:nil repeats:YES];
}

- (void)stopAnimating
{
    [animTimer invalidate];
}

@end
  • 实现协议方法

    -(void)onUpdate    {
    
        [animator setCurrentFrame:([animator currentFrame] + 1)%[animator numberOfFrames]];
    
        NSImage* image = [NSImage imageNamed:[NSString stringWithFormat:@"icon%ld", (long)[animator currentFrame]]];
    
        [statusItem setImage:image];
    
    }
    

  • 最近在一个简单的项目中,我不得不做一些类似的事情,所以我发布了用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
            }
        }
    }
    
    用法:

    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()
    }
    

    嗯,我想给人的印象是,该应用程序正在处理数据——这种情况很少发生,但最好知道。或者我不应该?这是一个合理的用途。见鬼,时间机器能做到。我认为Dropbox处理得很好。这很微妙,但它告诉你事情正在更新。时间机器过去就是这么做的。这在macOS 10.15中不会发生。是否也可以在状态栏项上放置NSView或NSImageView?如何操作?您必须通过[animTimer fire]通知animTimer启动还是自动启动?方法将为您将计时器添加到运行循环中(这是
    计划的
    位),因此您不需要自己启动计时器。-(无效)updateImage:(NSTimer*)timer add currentFrame++;谢谢,我添加了计数器递增。
    
    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()
    }