NSButton: показывать альтернативное изображение при наведении

У меня есть NSButton с изображением и альтернативным изображением. Я хотел бы, чтобы альтернативное изображение было показано при наведении курсора. Чтобы решить эту проблему, я расширил NSButton, чтобы показывать альтернативное изображение при наведении на изображение. Есть ли лучшее решение для этого?

Мое решение:

@interface HoverButton()
@property (nonatomic, strong) NSTrackingArea *trackingArea;
@property (nonatomic, strong) NSImage *imageTmp;
@end

@implementation HoverButton

-(void)mouseEntered:(NSEvent *)theEvent {
    [super mouseEntered:theEvent];

    [self updateImages];
    self.image = self.alternateImage;
}

-(void)mouseExited:(NSEvent *)theEvent {
    [super mouseExited:theEvent];

    self.image = self.imageTmp;
}

- (void)updateImages {
    self.imageTmp = self.image;
}

-(void)updateTrackingAreas
{
    if(self.trackingArea != nil) {
        [self removeTrackingArea:self.trackingArea];
    }

    int opts = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways);
    self.trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds]
                                                     options:opts
                                                       owner:self
                                                    userInfo:nil];

    [self addTrackingArea:self.trackingArea];
}


@end

2 ответа

Решение

Я бы сказал, что это лучше подходит для NSButtonCell подкласс. Вы можете сделать это одним способом, и он не будет применяться ко всем NSButton (я сомневаюсь, что это то, что вы на самом деле хотите). Просто установите тип ячейки кнопки в IB на свой подкласс.

Вот код, который я только что написал и протестировал, который работает:

- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
    if (_alternateImageOrKeyEquivalentFont && _bcFlags2.mouseInside) {
        // the draw bezel call is optional. maybe you don't want it
        [self drawBezelWithFrame:cellFrame inView:controlView];
        [self drawImage:_alternateImageOrKeyEquivalentFont
              withFrame:cellFrame
                 inView:controlView];
    } else {
        [super drawInteriorWithFrame:cellFrame
                              inView:controlView];
    }
}

вам нужно будет установить showsBorderOnlyWhileMouseInside в YES вероятно, в init метод для клетки.

CustomButton.h

@interface CustomButton : NSButton
@property (getter=isMouseInside) BOOL mouseInside;
@end

CustomButton.m

@implementation CustomButton

+ (Class)cellClass
{
    return [CustomButtonCell class];
}

- (instancetype)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        [self commonCustomButtonInit];
    }
    return self;
}

- (void)commonCustomButtonInit
{
    NSTrackingArea *trackingArea = nil;
    trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds]
                                                options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect
                                                  owner:self
                                               userInfo:nil];

    [self addTrackingArea:trackingArea];
}


- (void)mouseEntered:(NSEvent *)event
{
    self.mouseInside = YES;
    if ([self.cell isKindOfClass:[CustomButtonCell class]])
    {
        CustomButtonCell *cell = self.cell;
        cell.mouseInside = YES;
    }
}

-(void)mouseExited:(NSEvent *)event
{
    self.mouseInside = NO;
    if ([self.cell isKindOfClass:[CustomButtonCell class]])
    {
        CustomButtonCell *cell = self.cell;
        cell.mouseInside = NO;
    }
}

@end

CustomButtonCell.h

@interface CustomButtonCell : NSButtonCell
@property (getter=isMouseInside) BOOL mouseInside;
@end

CustomButtonCell.m

@implementation CustomButtonCell
@end

Также смотрите этот ответ.

Другие вопросы по тегам