通过拖动其他视图上方的 NSView 来移动 NSWindow

问题描述 投票:0回答:1

我有一个 macOS 应用程序,其中包含 NSTableView 和 NSVisualEffectView。视觉效果视图就像窗口底部的一个栏,它位于表格视图中(包含一些按钮/等...)。

无论如何,如果我想通过拖动视觉效果视图来移动 NSWindow,只有当表格视图不在视觉效果视图下方时才有效。我希望视觉效果视图位于表格视图之上的原因是,当用户滚动表格视图内容时,我可以获得很好的模糊效果。

但是,当视觉效果视图位于表格视图之上时,鼠标/拖动/等事件不会被注册。相反,它们被传递到表视图。我怎样才能阻止这种情况发生?

我尝试子类化 NSVisualEffectView,但我尝试的一切都失败了。这是我的代码:

#import <Cocoa/Cocoa.h>

@interface BottomMainBar : NSVisualEffectView {
    
}

@end

实现代码如下:

#import "BottomMainBar.h"

@implementation BottomMainBar

/// DRAW RECT METHOD ///

-(void)drawRect:(NSRect)dirtyRect {
    [super drawRect:dirtyRect];
    
    [self setWantsLayer:YES];
    
    [self.window setMovableByWindowBackground:YES];
    
    [self setAcceptsTouchEvents:YES];
    
    [self registeredDraggedTypes];
}

/// OTHER METHODS ///

-(BOOL)mouseDownCanMoveWindow {
    return YES;
}

-(BOOL)acceptsFirstMouse:(NSEvent *)event {
    return YES;
}

-(void)mouseDown:(NSEvent *)event {}
-(void)mouseDragged:(NSEvent *)event {}
-(void)mouseUp:(NSEvent *)event {}
-(void)mouseEntered:(NSEvent *)event {}
-(void)mouseExited:(NSEvent *)event {}

@end

我尝试过的方法都不起作用,如何阻止视觉效果视图将鼠标事件传递到其下面的图层?

objective-c macos cocoa nsview nswindow
1个回答
1
投票

最后我设法找到了一个解决方案,值得庆幸的是它不涉及任何库或开源代码(显然也没有私有 api)。

问题

我有一个

NSVisualEffectView
横跨我的视图控制器的宽度,高度为 38 px。它位于我的视图控制器的顶部。它充当包含一些按钮和标签的自定义工具栏。它位于显示各种内容(图像、视频、文本等)的
NSTableView
上方。

我将视觉效果视图放置在表格视图上方,因为我希望当用户滚动表格视图时有一个很好的模糊效果。这样做的问题是,视觉效果视图上的鼠标按下事件会传递到表格视图,而不是整体NSWindow。这导致用户在单击并拖动视觉效果视图时无法拖动和移动

NSWindow
(因为鼠标按下事件不会传递到窗口)。

我注意到视觉效果的顶部 10px

DID

将鼠标按下事件传递到窗口而不是表格视图。这是因为窗口的标题栏大约 10-15 像素高。然而我的视觉效果视图的高度是 38px,所以我的视觉效果视图的下半部分无法移动窗口。

解决方案

解决方案涉及创建两个子类,一个用于视觉效果视图,另一个用于

NSWindow

。视觉效果视图的子类,只需将鼠标按下事件传递给

nextResponder
(可以是表格视图或窗口 - 取决于窗口标题栏的大小)。

标题代码(视觉效果视图类):

#import <Cocoa/Cocoa.h> @interface TopMainBar : NSVisualEffectView { } @end

实现代码(视觉效果View类):

#import "TopMainBar.h" @implementation TopMainBar /// INIT WITH FRAME /// -(id)initWithFrame:(NSRect)frameRect { if ((self = [super initWithFrame:frameRect])) { [self setWantsLayer:YES]; [self.window setMovableByWindowBackground:YES]; } return self; } /// MOUSE METHODS /// -(void)mouseDown:(NSEvent *)event { [self.window mouseDown:event]; } @end

窗口的子类涉及将窗口标题栏变成工具栏,这实际上增加了标题栏的大小(并且恰好将其增加到大约 38 px,这正是我所需要的)。理想的解决方案是能够将标题栏高度增加到任何自定义尺寸,但这是不可能的,因此工具栏解决方案是唯一的方法。

由于标题栏的大小增加,所有鼠标按下事件都不会传递到窗口而不是表格视图。这使用户能够从视觉效果视图的任何部分拖动窗口。

头代码(Window类):

#import <Cocoa/Cocoa.h> @interface CustomWindow : NSWindowController <NSWindowDelegate> { } // UI methods. -(BOOL)isWindowFullScreen; @end

实现代码(Window类):

#import "CustomWindow.h" @interface CustomWindow () @end @implementation CustomWindow /// WINDOW DID LOAD /// -(void)windowDidLoad { [super windowDidLoad]; // Ensure this window is the current selected one. [self.window makeKeyAndOrderFront:self]; // Ensure the window can be moved. [self.window setMovableByWindowBackground:YES]; // Set the window title bar options. self.window.titleVisibility = NSWindowTitleHidden; self.window.titlebarAppearsTransparent = YES; self.window.styleMask |= (NSWindowStyleMaskFullSizeContentView | NSWindowStyleMaskUnifiedTitleAndToolbar | NSWindowStyleMaskTitled); self.window.movableByWindowBackground = YES; self.window.toolbar.showsBaselineSeparator = NO; self.window.toolbar.fullScreenAccessoryView.hidden = YES; self.window.toolbar.visible = ![self isWindowFullScreen]; } /// UI METHODS /// -(BOOL)isWindowFullScreen { return (([self.window styleMask] & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen); } /// WINDOW METHODS /// -(void)windowWillEnterFullScreen:(NSNotification *)notification { self.window.toolbar.visible = NO; } -(void)windowDidEnterFullScreen:(NSNotification *)notification { self.window.toolbar.visible = NO; } -(void)windowWillExitFullScreen:(NSNotification *)notification { self.window.toolbar.visible = YES; } -(void)windowDidExitFullScreen:(NSNotification *)notification { self.window.toolbar.visible = YES; } /// OTHER METHODS /// -(BOOL)mouseDownCanMoveWindow { return YES; } @end

在自定义窗口类中,您可以看到我正在根据窗口的全屏状态更改工具栏可见性。这是为了当窗口进入全屏模式时,标题栏不再出现并覆盖我的自定义视觉效果视图。

为了使其工作,您需要向窗口添加一个空工具栏,您可以在界面生成器中通过将

NSToolbar

对象拖放到窗口中来完成此操作。


确保将窗口连接到窗口委托,否则将不会调用全屏委托方法。

结论

此解决方案涉及通过将标题栏更改为工具栏来增加标题栏的大小。然后,从视觉效果视图类传递的鼠标按下事件由窗口(而不是其后面的任何其他视图)读取,因此可以移动窗口。

© www.soinside.com 2019 - 2024. All rights reserved.