Cocoa Objective-C macOS 应用程序中的 NSButton 增长-收缩动画

NSButton grow-shrink animation in Cocoa macOS application in Objective-C

我在 Objective-C 中有一个 mac 应用程序。

其中,我希望我的按钮在几秒钟后像成长一样动画。

我在 Cocoa 应用程序中找不到任何内容。

[UIView beginAnimations:nil context:NULL];
CGRect pos=v2.bounds;
pos.size.height=500;
pos.size.width=500;
[UIView setAnimationDuration:1.0];

[UIView setAnimationRepeatCount:15];
[UIView setAnimationRepeatAutoreverses:YES];
v2.bounds=pos;
[UIView commitAnimations];

我在 ios 中使用了上面的代码来增加一个按钮,但是如何在 cocoa mac 应用程序中实现这一点?

所以基本上我想要一个 NSButton 的放大和缩小动画。

在cocoa中您有多种动画方式,您可能需要选择一种适合您的方式。例如,您可以使用 NSAnimationContext 来完成此任务,代码如下:

- (IBAction)buttonPressed:(id)sender {
    [self runAnimations:10];
}

- (void)runAnimations:(NSUInteger)repeatCount {

    CGFloat oldWidth = self.buttonWidthConstraint.constant;
    CGFloat oldHeight = self.buttonHeightConstraint.constant;

    [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
        context.duration = 1.;
        self.buttonWidthConstraint.animator.constant = 500;
        self.buttonHeightConstraint.animator.constant = 500;
    } completionHandler:^{
            //change back to original size
            [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
                context.duration = 1.;
                self.buttonWidthConstraint.animator.constant = oldWidth;
                self.buttonHeightConstraint.animator.constant = oldHeight;
            } completionHandler:^{
                if (repeatCount - 1 > 0) {
                    [self runAnimations:repeatCount - 1];
                }
            }];
    }];
}

最好为既不直接使用 bounds 操作的约束设置动画。但是,如果您真的需要 - 您可以根据需要采用此代码。

可以在 WWDC 2013, Best Practices for Cocoa Animation 中看到有关您在 OSX 上的所有动画选项的精彩视频,我鼓励您完整地观看它。

以下是 Swift5 中的一些示例。

@IBOutlet weak var burpButton: NSButton!
@IBOutlet weak var rotateButton: NSButton!
@IBOutlet weak var flashButton: NSButton!


override func viewDidLoad() {
    super.viewDidLoad()

    rotateButton.wantsLayer = true
    flashButton.wantsLayer = true
    burpButton.wantsLayer = true

    flashButton.layer?.cornerRadius = 30
    flashButton.layer?.masksToBounds  = true
    flashButton.layer?.borderWidth = 2
    flashButton.layer?.borderColor = NSColor.blue.cgColor


    rotateButton.layer?.backgroundColor = NSColor.systemRed.cgColor
    flashButton.layer?.backgroundColor = NSColor.systemYellow.cgColor
    burpButton.layer?.backgroundColor = NSColor.systemBlue.cgColor
}



@IBAction func rotateButtonPressed(sender: NSButton) {
    runRotateAnimations(repeatCount: 10)

}

func runRotateAnimations(repeatCount: Int) {
    let rotate = CABasicAnimation(keyPath: "transform.rotation")
    rotate.fillMode = CAMediaTimingFillMode.forwards
    rotate.fromValue = 0.0
    rotate.toValue = CGFloat(Double.pi * -2.0)
    rotate.duration = 1
    rotate.repeatCount = Float.init(exactly: 1)!
    rotateButton.layer?.position = CGPoint.init(x: rotateButton.frame.midX, y: rotateButton.frame.midY)

    //Make(sender.frame.midX, sender.frame.midY)
    rotateButton.layer?.anchorPoint = CGPoint.init(x: 0.5, y: 0.5)
    rotateButton.layer?.add(rotate, forKey: nil)
}


@IBAction func burpButtonPressed(sender: NSButton) {
    runBurpAnimations()
}


func runBurpAnimations() {

    burpButton.layer?.anchorPoint = CGPoint.init(x: 0.5, y: 0.5)
    let burp = CABasicAnimation(keyPath: "transform.scale")
    burp.fromValue = 0.0
    burp.toValue = 1.50 //CGPoint(x: bigWidth, y: bigHeight)
    burp.duration = 0.35
    //burp.repeatCount = Float.init(exactly: 1)!
    burp.repeatCount = 2
    burp.autoreverses = true
    //burp.speed = 0.75

    burpButton.layer?.position = CGPoint.init(x: burpButton.frame.midX, y: burpButton.frame.midY)
    burpButton.layer?.add(burp, forKey: nil)

}


@IBAction func flashButtonPressed(sender: NSButton) {
    runFlashAnimations()
}

func runFlashAnimations() {
    let flash = CABasicAnimation(keyPath: "opacity")
    flash.duration = 0.3
    flash.fromValue = 1
    flash.toValue = 0.1
    flash.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
    flash.autoreverses = true
    flash.repeatCount = 2
    flashButton.layer?.add(flash, forKey: nil)
}

我从@SegaZero 那里得到了一些想法。一些来自 this medium article。虽然这篇文章是关于 iOS,但不难找到适用于 macOS 的可用元素。