Pergunta

I want to animate the width of my button in my Mac App and at the same time have a background image and a foreground image. For that I'm using @kgn's awesome library BBlock (https://github.com/kgn/BBlock).

Problem is that the background image seems to get drawn behind each other, so when the button scales down, you can't even see the background image animation and it seems to be cut off. Button Image Cut Off

This way of "animating" the width change works if I just use setImage, but then I don't get the benefits of having a background image.

I've made a custom button that scales the button incrementally (basically animates it). It changes the size of the button by one pixel each run and changes the image, background image and alternate background image by one pixel as well:

- (void)scaleTestButtonUntilWidth:(int)width{
    [NSTimer scheduledTimerRepeats:YES withTimeInterval:timeInterval andBlock:^{
        if (self.width == width) {
            return;
        }

        int newSize;
        if (width > self.width) {
            newSize = self.width += 1;
        }else if (width < self.width){
            newSize = self.width -= 1;
        }

        self.width = newSize;
        [self setImage:self.image];
        [self setAlternateBackgroundImage:[self alternateBGImage]];
        [self setBackgroundImage:[self BGImage]];
    }];
}

The setBackgroundImage looks like this and the implementation for setAlternateBackgroundImage is the same:

- (void)setBackgroundImage:(NSImage *)backgroundImage{
    [self setImage:[self imageWithBackgroundImage:backgroundImage
                                          andIcon:self.image]];
    [self setButtonType:NSMomentaryChangeButton];
    [self setBordered:NO];
}

Which calls the method that actually draws the image:

- (NSImage *)imageWithBackgroundImage:(NSImage *)background andIcon:(NSImage *)icon{
    return [NSImage imageForSize:background.size withDrawingBlock:^{
        NSRect bounds = NSZeroRect;
        bounds.size = background.size;

        NSRect iconRect = NSZeroRect;
        iconRect.size = icon.size;
        iconRect.origin.x = round(background.size.width*0.5f-iconRect.size.width*0.5f);
        iconRect.origin.y = round(background.size.height*0.5f-iconRect.size.height*0.5f);

        [background drawInRect:bounds fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0f];
        [icon drawInRect:iconRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0f];
    }];
} 

With the help of this method:

+ (NSImage *)imageForSize:(NSSize)size withDrawingBlock:(void(^)())drawingBlock{
    if(size.width <= 0 || size.width <= 0){
        return nil;
    }

    NSImage *image = [[NSImage alloc] initWithSize:size];

    [image lockFocus];
    drawingBlock();
    [image unlockFocus];
#if !__has_feature(objc_arc)
    return [image autorelease];
#else
    return image;
#endif
}
Foi útil?

Solução

I wonder if you would be better off subclassing NSButton and overwriting drawRect

Outras dicas

Maybe try saving and restoring the graphics context.

return [NSImage imageForSize:background.size withDrawingBlock:^{
    NSRect bounds = NSZeroRect;
    bounds.size = background.size;

    NSRect iconRect = NSZeroRect;
    iconRect.size = icon.size;
    iconRect.origin.x = round(background.size.width*0.5f-iconRect.size.width*0.5f);
    iconRect.origin.y = round(background.size.height*0.5f-iconRect.size.height*0.5f);

    CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
    CGContextSaveGState(context);        
    [background drawInRect:bounds fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0f];
    [icon drawInRect:iconRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0f];
    CGContextRestoreGState(context);
}];
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top