允许单击并拖动视图以拖动窗口本身?

d11*_*wtq 18 macos cocoa objective-c appkit nswindow

我正在使用一个带纹理的窗口,它的顶部有一个标签栏,位于标题栏的下方.

我已经-setContentBorderThickness:forEdge:在窗口上使用了渐变效果,并确保纸张从正确的位置滑出.

然而,什么不起作用是拖动窗口.如果我点击并拖动实际上是标题栏的区域,但是由于标题栏渐变溢出到(可能/通常是空的)标签栏,它容易点击太低而且当你试图拖动时感觉非常令人沮丧并意识到窗户没有移动.

我注意到NSToolbar,当标题栏下方占据的空间大致相同时,允许在光标位于其上时拖动窗口.如何实现这一点?

谢谢.

标签栏

Art*_*are 25

我尝试了mouseDownCanMoveWindow解决方案(/sf/answers/319490251/),但它对我不起作用.我摆脱了那个方法,而是将它添加到我的窗口子类中:

- (BOOL)isMovableByWindowBackground {
    return YES;
}
Run Code Online (Sandbox Code Playgroud)

这就像一个魅力.

  • 在Swift中:`window.movableByWindowBackground = true`. (9认同)
  • @Odin - 我想象`window.movableByWindowBackground = YES;`在Obj-C中工作,但我认为我去了覆盖路由的方法,因为我特意想要创建一个始终显示这个特征的`NSWindow`的子类. (3认同)

d11*_*wtq 16

我在这里找到了这个:

-(void)mouseDown:(NSEvent *)theEvent {    
    NSRect  windowFrame = [[self window] frame];

    initialLocation = [NSEvent mouseLocation];

    initialLocation.x -= windowFrame.origin.x;
    initialLocation.y -= windowFrame.origin.y;
}

- (void)mouseDragged:(NSEvent *)theEvent {
    NSPoint currentLocation;
    NSPoint newOrigin;

    NSRect  screenFrame = [[NSScreen mainScreen] frame];
    NSRect  windowFrame = [self frame];

    currentLocation = [NSEvent mouseLocation];
    newOrigin.x = currentLocation.x - initialLocation.x;
    newOrigin.y = currentLocation.y - initialLocation.y;

    // Don't let window get dragged up under the menu bar
    if( (newOrigin.y+windowFrame.size.height) > (screenFrame.origin.y+screenFrame.size.height) ){
        newOrigin.y=screenFrame.origin.y + (screenFrame.size.height-windowFrame.size.height);
    }

    //go ahead and move the window to the new location
    [[self window] setFrameOrigin:newOrigin];
}
Run Code Online (Sandbox Code Playgroud)

它工作正常,但我不是100%确定我正确地做到了.到目前为止我发现了一个错误,如果拖动开始在子视图(标签本身)内,然后进入超级视图(标签栏).窗户跳了起来.一些-hitTest:magic,或者甚至可能只是使mouseUp上的initialLocation无效应该可以解决这个问题.


Ric*_*ard 11

您是否尝试重写NSView方法mouseDownCanMoveWindow以返回YES

  • 我的下一个想法是覆盖`mouseDown:`(NSControl方法)将鼠标事件传递给`[self window]`,并确保窗口`isMovableByWindowBackground`,但这对我来说仍然不起作用.抱歉. (3认同)

Nix*_*ang 10

经过两个步骤后它适用于我:

  1. 子类NSView,覆盖mouseDownCanMoveWindow返回YES.
  2. 子类NSWindow,覆盖isMovableByWindowBackground返回YES.

  • 你不需要子类化NSWindow,因为你可以在视图控制器中调用`[self.view.window setMovableByWindowBackground:YES]`.看起来NSWindow的`isMovableByWindowBackground`是可变的,而NSView的`mouseDownCanMoveWindow`是只读的. (6认同)
  • 如果您使窗口"纹理化",则可以跳过第二步.(IB中有一个复选框.) (2认同)

Dim*_*iol 8

从macOS 10.11开始,最简单的方法是使用新-[NSWindow performWindowDragWithEvent:]方法:

@interface MyView () {
    BOOL movingWindow;
}
@end

@implementation MyView

...

- (BOOL)mouseDownCanMoveWindow
{
    return NO;
}

- (void)mouseDown:(NSEvent *)event
{
    movingWindow = NO;

    CGPoint point = [self convertPoint:event.locationInWindow
                              fromView:nil];

    // The area in your view where you want the window to move:
    CGRect movableRect = CGRectMake(0, 0, 100, 100);

    if (self.window.movableByWindowBackground &&
        CGRectContainsPoint(movableRect, point)) {

        [self.window performWindowDragWithEvent:event];
        movingWindow = YES;
        return;
    }

    // Handle the -mouseDown: as usual
}

- (void)mouseDragged:(NSEvent *)event
{
    if (movingWindow) return;

    // Handle the -mouseDragged: as usual
}

@end
Run Code Online (Sandbox Code Playgroud)

这里,-performWindowDragWithEvent:将处理不重叠菜单栏的正确行为,并且还将捕捉到macOS 10.12及更高版本的边缘.确保BOOL movingWindow在视图的私有界面中包含一个实例变量,这样-mouseDragged:一旦确定不想处理它们,就可以避免发生事件.

在这里,我们还检查-[NSWindow movableByWindowBackground]是否设置YES为此视图可以在不可移动的窗口背景窗口中使用,但这是可选的.