Change NSWindow background color with FadeIn Animation - macos

I'm trying to build a Mac App (for the second time) and want to change the background color of my NSWindow with a fadein animation.
Right now, I've set the background image in this way:
NSImage *windowBG = [NSImage imageNamed:#"greenBG.png"];
[[self.window contentView] setWantsLayer:YES];
[[self.window contentView] layer].contents = windowBG;
On a particular event, I want to change the "greenBG.png" to "yellowBG.png" with a fadein animation.
Doing this in iOS is simpler, but how can this be done in Cocoa?

Related

tvOS Gesture Recognizer stops working after sliding offscreen

I have a view that acts like the macOS dock - it can be moved offscreen entirely.
My gesture recognizer looks like:
-(void)swipeDown:(UISwipeGestureRecognizer *)sender
{
NSLog(#"Swipe Down");
// this should move the dock 10 pixels below the bottom of the screen
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{[self dockView].frame = CGRectMake(kSafeMarginHorizontal, self.view.frame.size.height + 10, self.view.frame.size.width - (kSafeMarginHorizontal * 2), 80);}
completion:nil];
}
I am only using an autoresizing mask on my dockView with right and left edges pinned. In my main parent view I call:
[[self view] setTranslatesAutoresizingMaskIntoConstraints:YES];
This works fine, but after sliding offscreen, the corresponding Swipe Up gesture no longer works and if I swipe down again, I no longer get the NSLog indicating the method was called.
I can prevent this by not sliding the view entirely offscreen. If I leave a least a few pixels on the screen, it continues to work ok.
Why does this break my gesture recognizer?
It seems that tvOS does not like it when a focused button ends up offscreen. I have also changed this to animate by changing constraints. The key is calling setNeedsFocusUpdate at the end of the animation.
// flush pending layout operations, then animate the constraint change
[[self view] layoutIfNeeded];
[UIView animateWithDuration:0.25
delay:0.0
options:UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionAllowUserInteraction
animations:^{[[self dockViewConstraint] setConstant:1080];
[[self view] layoutIfNeeded];}
completion:^(BOOL finished){
// Do some cleanup after animating.
[self setNeedsFocusUpdate];}];

NSAnimation removes button background colour

I am working on a Mac app. I am trying to do a simple animation which makes an NSButton move down. The animation works really nicely, but when i do it, the background colour of my NSButton disappears for some reason. Here is my code:
// Tell the view to create a backing layer.
additionButton.wantsLayer = YES;
// Set the layer redraw policy. This would be better done in
// the initialization method of a NSView subclass instead of here.
additionButton.layerContentsRedrawPolicy = NSViewLayerContentsRedrawOnSetNeedsDisplay;
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
context.duration = 1.0f;
additionButton.animator.frame = CGRectOffset(additionButton.frame, 0.0, -20.0);
//additionButton.frame = CGRectOffset(additionButton.frame, 0.0, -20.0);
} completionHandler:nil];
Button move down animation:
Button after move down animation:
Update 1
Just to make it clear, I am not using a background image in my buttons. I am using a background NSColor which I set in the viewDidLoad method like so:
[[additionButton cell] setBackgroundColor:[NSColor colorWithRed:(100/255.0) green:(43/255.0) blue:(22/255.0) alpha:1.0]];
I presume this is an AppKit bug. There are a couple of ways you can work around it.
Workaround 1:
Don't use layers. The button you're animating seems to be small, and you might be able to get away with using a non layer-backed animation and still have it look decent. The button will redraw during each step of the animation, but it will animate correctly. That means this is really all you have to do:
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
additionButton.animator.frame = CGRectOffset(additionButton.frame, 0, -20);
} completionHandler:nil];
Workaround 2:
Set the background color on the layer.
additionButton.wantsLayer = YES;
additionButton.layer.backgroundColor = NSColor.redColor.CGColor;
additionButton.layerContentsRedrawPolicy = NSViewLayerContentsRedrawOnSetNeedsDisplay;
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
additionButton.animator.frame = CGRectOffset(additionButton.frame, 0, -20);
} completionHandler:nil];
Workaround 3:
Subclass NSButtonCell, and implement -drawBezelWithFrame:inView:, drawing your background color there. Keep in mind that the parent view containing the button should be layer-backed, otherwise the button will still redraw on every step.

How do I tint an application window like this one?

I am very new to OSX development.
How do I tint an application to dark gray like this one did?
is it possible to do that from interface builder? If not, how do I do that from code?
To change window title bar color, set the window as textured in IB. Then in corresponding view controller/app delegate update the window color.
NSColor *grayColor = [NSColor colorWithCalibratedRed:64/255.0f
green:64/255.0f
blue:64/255.0f
alpha:1.0];
[self.window setBackgroundColor:grayColor];
Now the window would like this :
With Toolbar:
Note that when window is set as textured entire window will be textured. I have subclassed the view and set background to white color :
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
[[NSColor whiteColor] setFill];
NSRectFill(dirtyRect);
}
Else the window would like this :

Lion compound animations for full screen

I'm transitioning a window to full screen mode (the new Lion kind of full screen mode). While I do the transition, I'd like to also slide one of the views in my NSWindow to a new position.
So, in my NSWindowDelegate, I've tried returning the window and implementing the custom animation:
- (NSArray *)customWindowsToEnterFullScreenForWindow:(NSWindow *)window
{
return [NSArray arrayWithObject: window];
}
- (void)window:(NSWindow *)_window startCustomAnimationToEnterFullScreenWithDuration:(NSTimeInterval)duration
{
// book is NSView *ivar
[[book animator] setFrame: NSMakeRect(/*computed rect*/)];
}
But this completely kills the default animation of going to full-screen mode and my window suddenly doesn't paint correctly.
Is there some way to compound these while still using the default animation? I'm pretty new to core animation beyond [view animator] level stuff, So I'm sure I'm screwing up something quite simple.
You have to write something like this in order to have the two animations in sync:
- (void)window:(NSWindow *)_window startCustomAnimationToEnterFullScreenWithDuration:(NSTimeInterval)duration
{
// book is NSView *ivar
[[NSAnimationContext currentContext] setDuration:duration];
[[book animator] setFrame: NSMakeRect(/*computed rect*/)];
}

cocoa -- getting nested NSViews and CALayers to resize proportionally

My NSWindow's contentView is an NSView subclass. It has some other NSView subclasses as subviews. The subviews are layer-based, and those layers in turn contain sublayers. Some of the sublayers have further sub-sublayers.
I want the whole thing to resize proportionally when the window is resized. What is the right way to set it up so that will happen?
Thanks
EDIT: I am not using Interface Builder at all.
Here's what I've done to get the contents of an NSView to scale proportionally as I resize the parent window. First, in interface builder, I added my NSView to the window, then added a reference to it in my AppDelegate. Mine happens to be called scrollView. I removed all of the auto-sizing behaviour from the scrollView.
Then, in my AppDelegate I added this:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// keep the aspect ratio constant so that the content looks good
[window setContentAspectRatio:NSMakeSize(2, 1)];
window.delegate = self;
}
- (void)windowDidResize:(NSNotification *)notification {
// size the scrollView to fill the window, but keep its bounds constant
NSRect rect = [[window contentView] frame];
NSRect oldBounds = [scrollView bounds];
[scrollView setFrame:rect];
[scrollView setBounds:oldBounds];
}
This turns the AppDelegate into the window delegate too. Fine since I've not got much logic in it. By keeping the bounds constant while changing the frame, the contents of scrollView will be scaled down smoothly.

Resources