Manthan
Manthan

Reputation: 3914

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

I am having a mac app in Objective-C.

In which, I want my button to animate like grow after some seconds.

I couldn't find anything in Cocoa application.

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

I used the above code in ios to grow a button but how to make this happen in cocoa mac application?

So basically I want a grown and shrink animation of an NSButton.

Upvotes: 1

Views: 2469

Answers (2)

ICL1901
ICL1901

Reputation: 7778

Here are a few examples in 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)
}

I got some ideas from @SegaZero. Some from this medium article. While the article is about iOS, it's not hard to find usable elements for macOS.

Upvotes: -1

Sega-Zero
Sega-Zero

Reputation: 3017

In cocoa you have a several ways of animations, you probably need to chose an appropriate for you. For instance you can use NSAnimationContext for this task with a code like this:

- (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];
                }
            }];
    }];
}

It is much better to animate a constraints neither operating with bounds directly. But if you really need to - you can adopt this code to whatever you want.

A great video about all the options you have on OSX for animations may be seen in WWDC 2013, Best Practices for Cocoa Animation, I encourage you to watch it completely.

Upvotes: 3

Related Questions