При создании пользовательского 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