objective-ccocoansviewnscolornsgradient

Change NSGradient colors in OSX 10.7 and 10.8


I have a NSView subclass named OneView with the following code:

#import "OneView.h"

@interface OneView ()
@property (strong, nonatomic) NSGradient *gradient;
@end

@implementation OneView

- (void)drawRect:(NSRect)dirtyRect {

    [super drawRect:dirtyRect];

    NSColor *top = [NSColor colorWithCalibratedRed:1.0 green:0.0 blue:0.0 alpha:1.0];
    NSColor *btm = [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];

    self.gradient = [[NSGradient alloc] initWithStartingColor:top endingColor:btm];
    [self.gradient drawInRect:self.bounds angle:270];
}

# pragma mark - Public

- (void)changeGradient {

    self.gradient = nil;

    NSColor *top = [NSColor colorWithCalibratedRed:0.0 green:1.0 blue:0.0 alpha:1.0];
    NSColor *btm = [NSColor colorWithCalibratedRed:0.0 green:0.0 blue:0.0 alpha:1.0];

    self.gradient = [[NSGradient alloc] initWithStartingColor:top endingColor:btm];
    [self.gradient drawInRect:self.bounds angle:270];

    [self setNeedsDisplay:YES];
}

@end

In my AppDelegate (or could be any other class), I am trying to change the colors of the gradient by calling the changeGradient method of the OneView class:

#import "AppDelegate.h"
#import "OneView.h"

@interface AppDelegate ()
@property (weak, nonatomic) IBOutlet OneView *oneView;
@end

@implementation AppDelegate


- (IBAction)changeGradient:(id)sender {
    [self.oneView changeGradient];
}

@end

When the view is first loaded the gradient is initialized as expected but I am unable to change the gradient from the IBAction method. I have achieved this using layer backed views but I am trying to find a way that doesn't rely on layers for backwards compatibility.

Any thoughts on why the IBAction is not changing the gradient?

enter image description here


Solution

  • The problem is self.gradient = [[NSGradient alloc] initWithStartingColor:top endingColor:btm]; inside drawRect: function. Change it to if (!self.gradient) { self.gradient = [[NSGradient alloc] initWithStartingColor:top endingColor:btm]; } will fix the issue. By the way, you shouldn't create gradient inside your drawRect: method. It will hurt the performance. In that case, should put the initialization in awakeFromNib method.