Cocoa/OSX - NSWindow standardWindowButton behaving strangely once copied and added again

佐手、 提交于 2019-11-30 02:45:14

Here is the mechanics of this hover magic: Before drawing itself standard circled button (such as NSWindowMiniaturizeButton) calls their superview undocumented method _mouseInGroup:. If this method returns YES circled button draws itself with icon inside. That's all.

If you place these buttons inside your own view, you can simply implement this method and control this mouse-hover-appearance as you want. If you just move or relayout these buttons and they still be subviews of NSThemeFrame (or something similar), you have to swizzle method _mouseInGroup: for this class, and probably it doesn't worth it because we have perfectly simple previous method.

In my case I have custom NSView that contains my standard buttons as subviews and this code makes all described above magic:

- (void)updateTrackingAreas
{
    NSTrackingArea *const trackingArea = [[NSTrackingArea alloc] initWithRect:NSZeroRect options:(NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect) owner:self userInfo:nil];
    [self addTrackingArea:trackingArea];
}

- (void)mouseEntered:(NSEvent *)event
{
    [super mouseEntered:event];
    self.mouseInside = YES;
    [self setNeedsDisplayForStandardWindowButtons];
}

- (void)mouseExited:(NSEvent *)event
{
    [super mouseExited:event];
    self.mouseInside = NO;
    [self setNeedsDisplayForStandardWindowButtons];
}

- (BOOL)_mouseInGroup:(NSButton *)button
{
    return self.mouseInside;
}

- (void)setNeedsDisplayForStandardWindowButtons
{
    [self.closeButtonView setNeedsDisplay];
    [self.miniaturizeButtonView setNeedsDisplay];
    [self.zoomButtonView setNeedsDisplay];
}
Cai

I'm fully aware that this question is old and Valentin Shergin's answer is correct. It prevents the utilize of any Private API, unlike Google did in Chrome. Just wanted to share a method for those who don't feel like subclass NSView just to put those buttons in an existed view (such as self.window.contentView).

As I just wanted to reposition the NSWindowButtons via setFrame:, I found out that once the window was resized, the tracking areas seems to "fix" themselves automagically, without any Private API usage (at least in 10.11).

Thus, you can do things like the following to apply "fake resize" to the window that you repositioned your buttons:

NSRect frame = [self.window frame];
frame.size = NSMakeSize(frame.size.width, frame.size.height+1.f);
[self.window setFrame:frame display:NO animate:NO];
frame.size = NSMakeSize(frame.size.width, frame.size.height-1.f);
[self.window setFrame:frame display:NO animate:YES];

(I did it within my main window's NSWindowDelegate windowDidBecomeMain:. Should work as long as the window is loaded and visible.)

You're not adding them again. You're moving them to contentView. The buttons are originally in window.contentView.superview.

[window.contentView.superview addSubview:closeButton];
[window.contentView.superview addSubview:fullScreenButton];
[window.contentView.superview addSubview:minitButton];

Should get you the correct behaviour without requiring a trackingArea.

Sumit utreja

Call [button highlight:yes] for each button.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!