【问题标题】:Clear before drawInRect for Mac App在 Mac App 的 drawInRect 之前清除
【发布时间】:2013-02-23 05:59:48
【问题描述】:

我想在我的 Mac 应用程序中为我的按钮宽度设置动画,同时有一个背景图像和一个前景图像。为此,我使用了@kgn 的很棒的库 BBlock (https://github.com/kgn/BBlock)。

问题是背景图像似乎被绘制在一个后面,所以当按钮缩小时,你甚至看不到背景图像动画,它似乎被切断了。

如果我只使用 setImage,这种“动画化”宽度变化的方式是有效的,但是我没有得到背景图像的好处。

我制作了一个自定义按钮,可以逐步缩放按钮(基本上是动画)。它每次运行都会将按钮的大小更改一个像素,并将图像、背景图像和备用背景图像也更改一个像素:

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

setBackgroundImage 看起来像这样,setAlternateBackgroundImage 的实现是一样的:

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

调用实际绘制图像的方法:

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

借助这个方法:

+ (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
}

【问题讨论】:

  • 没有建议?在绘制新图像之前,必须有某种方法可以清除背景。
  • 这听起来像是你实现 NSImage +imageForSize:withDrawingBlock: 的方式有问题。我假设你自己在一个类别中实现了它,因为它不是标准的 NSImage 方法。

标签: objective-c xcode macos nsimage


【解决方案1】:

我想知道你是否最好继承 NSButton 并覆盖 drawRect

【讨论】:

【解决方案2】:

也许尝试保存和恢复图形上下文。

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

【讨论】:

  • 不错的建议。虽然没有工作。这很奇怪,因为如果我只使用 [self setImage:[self BGImage]] 就可以了。然后我只是没有选择背景和前景图像。如果我发布整个代码流程会有帮助吗?!
猜你喜欢
  • 2018-11-03
  • 1970-01-01
  • 2016-11-08
  • 2011-06-28
  • 2023-02-09
  • 2020-06-05
  • 1970-01-01
  • 2013-11-12
  • 1970-01-01
相关资源
最近更新 更多