mouseExited больше не вызывается после mouseDown в подклассе NSButton. - PullRequest
0 голосов
/ 24 апреля 2018

При создании пользовательского NSButton я столкнулся с проблемой обработки поведения выделения. После нажатия кнопки вниз, удержания и перетаскивания курсора за пределы кнопки события mouseExited: и mouseEntered: не доставляются. Я понимаю причину, потому что в mouseDown: вызов [super mouseDown:event]; будет блокироваться до тех пор, пока не будет отпущен щелчок.

При изучении этого я наткнулся на этот пост переполнения стека , который описывает ту же проблему. Отмеченное решение состоит в том, чтобы добавить NSTrackingEnabledDuringMouseDrag к опциям NSTrackingArea, что я и сделал, но я продолжаю видеть эту проблему. Я попробовал другое предложенное решение с обработкой следующих событий в цикле, но это привело к странному поведению. Цвет текста кнопки становится черным при наведении курсора мыши вместо того, чтобы выделять затемненный цвет, и он не высвечивается при отпускании мыши, а остается черным.

Я использую Xcode 9.3, работающий на macOS 10.13.4.

Вот мой NSButton подкласс:

@interface BorderlessButton : NSButton {
    NSColor *_tempColor;
}

@property (strong, nonatomic) NSColor *color;

@end

@interface BorderlessButton ()

@property (nonatomic) BOOL pressed;

@end

@implementation BorderlessButton

- (id)init {
    if (self = [super init]) {
        [self setUp];
    }
    return self;
}

- (id)initWithFrame:(NSRect)frameRect {
    if (self = [super initWithFrame:frameRect]) {
        [self setUp];
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super initWithCoder:aDecoder]) {
        [self setUp];
    }
    return self;
}

- (void)setUp {
    _color = [NSColor redColor];

    [self setTitle:self.title];
    [self setButtonType:NSButtonTypeMomentaryChange];
    [self setBordered:NO];

    NSTrackingArea *area = [[NSTrackingArea alloc] initWithRect:self.bounds
                                                        options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingEnabledDuringMouseDrag
                                                          owner:self
                                                       userInfo:nil];
    [self addTrackingArea:area];
}

- (void)setTitle:(NSString *)title {
    [super setTitle:title];

    NSMutableAttributedString *colorTitle = [[NSMutableAttributedString alloc] initWithAttributedString:[self attributedTitle]];
    [colorTitle addAttributes:@{NSFontAttributeName: self.font, NSForegroundColorAttributeName: self.color} range:NSMakeRange(0, [colorTitle length])];
    [self setAttributedTitle:colorTitle];
}

- (void)setColor:(NSColor *)color {
    _color = color;

    [self setTitle:self.title];
}

- (void)mouseDown:(NSEvent *)event {
    self.pressed = YES;
    [self highlight:YES];
    [super mouseDown:event]; // this blocks until released
    [self mouseUp:event];
}

- (void)mouseUp:(NSEvent *)event {
    self.pressed = NO;
    [self highlight:NO];
    [super mouseUp:event];
}

//FIXME: Not called after mouse press down and hold then exit
- (void)mouseExited:(NSEvent *)event {
    if (self.pressed) {
        [self highlight:NO];
    }
    [super mouseExited:event];
}

- (void)mouseEntered:(NSEvent *)event {
    if (self.pressed) {
        [self highlight:YES];
    }
    [super mouseEntered:event];
}

- (void)highlight:(BOOL)flag {
    if (flag) {
        if (self.isEnabled) {
            NSColor *dimmedColor = [self dimmedColor];
            _tempColor = _color;
            self.color = dimmedColor;
            [self setTitle:self.title];
        }
    } else {
        if (self.isEnabled) {
            self.color = _tempColor;
            [self setTitle:self.title];
        }
    }
}

- (NSColor *)dimmedColor {
    return [self.color colorWithAlphaComponent:0.5];
}

@end
...