Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cocoa - animating NSWindow

Tags:

macos

swift

cocoa

I am trying to animate my NSWindow after I click a specific button, so I wrote a function:

func fadeIn(window: NSWindow, duration: NSTimeInterval) {
    var alpha = 0.0 as CGFloat
    window.alphaValue = alpha
    window.makeKeyAndOrderFront(nil)
    let numberOfLoops = Int(duration / 0.02)
    let alphaChangeInLoop = (CGFloat(1.0) / CGFloat(numberOfLoops))
    var loopRun = 0
    for _ in 0...numberOfLoops {
        loopRun += 1
        alpha += alphaChangeInLoop
        window.alphaValue = alpha
        NSThread.sleepForTimeInterval(0.020)
    }
    print("Loop was run \(loopRun) times. Ending alpha: \(alpha)")
    if alpha != 1.0 {
        alpha = 1.0
        window.alphaValue = 1.0
        print("Alpha set to 1.0")
    }
}

It seems OK for me, but it is not - the window does not fade in. It just appears after whatever I put in the duration field (so it is probably not accepting any alphaValue below 1.0).

Is it possible to animate alphaValue in OSX application? I've been searching this forum and I found some other ways including NSAnimationContext but it did not work for me.

like image 494
mdmb Avatar asked Jan 06 '23 08:01

mdmb


1 Answers

The problem with your approach is that the window typically only redraws when you let flow of execution return to the main event loop. You're not doing that until the end. You could try to force the window to redraw for each iteration of your loop, but don't bother.

Animation is built in to Cocoa. Try this:

    window.alphaValue = 0
    window.makeKeyAndOrderFront(nil)
    NSAnimationContext.runAnimationGroup({ (context) -> Void in
        context.duration = duration
        window.animator().alphaValue = 1
    }, completionHandler: nil)

If you're OK with the default duration of 0.25 seconds, you can just do:

    window.alphaValue = 0
    window.makeKeyAndOrderFront(nil)
    window.animator().alphaValue = 1

You should also be aware that Cocoa applies animations to windows, by default. You should consider just letting it do its thing. If you insist on taking over for it, you should probably do:

    window.animationBehavior = .None
like image 168
Ken Thomases Avatar answered Jan 16 '23 00:01

Ken Thomases