objective c - qué - ¿Permitir hacer clic y arrastrar una vista para arrastrar la ventana?
que es doble clic (7)
¿Ha intentado anular el método mouseDownCanMoveWindow
para devolver YES
?
Estoy usando una ventana con textura que tiene una barra de pestañas en la parte superior, justo debajo de la barra de título.
He usado -setContentBorderThickness:forEdge:
en la ventana para que el degradado se vea bien y para que las hojas se salgan de la posición correcta.
Lo que no funciona, sin embargo, es arrastrar la ventana. Funciona si hago clic y arrastro el área que en realidad es la barra de título, pero como el gradiente de la barra de título se derrama en una barra de pestañas (potencialmente / a menudo vacía), es muy fácil hacer clic en un nivel demasiado bajo y se siente realmente frustrante cuando intenta arrastrar Y darse cuenta que la ventana no se está moviendo.
NSToolbar
, mientras ocupa aproximadamente la misma cantidad de espacio debajo de la barra de título, permite que la ventana se arrastre cuando el cursor está sobre ella. ¿Cómo se implementa esto?
Gracias.
A partir de macOS 10.11, la forma más sencilla de hacerlo es utilizar el nuevo -[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
Aquí, -performWindowDragWithEvent:
manejará el comportamiento correcto de no superponerse a la barra de menú, y también se ajustará a los bordes en macOS 10.12 y posteriores. Asegúrese de incluir una variable de instancia BOOL movingWindow
con la interfaz privada de su vista para que pueda evitar los eventos -mouseDragged:
una vez que haya determinado que no desea procesarlos.
Aquí, también estamos verificando que -[NSWindow movableByWindowBackground]
esté configurado en YES
para que esta vista se pueda usar en ventanas de fondo no movible por ventana, pero eso es opcional.
Encontré esto here :
-(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];
}
Funciona bien, aunque no estoy 100% seguro de hacerlo correctamente. Hay un error que he encontrado hasta ahora, y eso es si el arrastre comienza dentro de una subvista (una pestaña en sí) y luego ingresa la vista de supervisión (la barra de pestañas). La ventana salta alrededor. Algún -hitTest: magic, o posiblemente incluso invalidando initialLocation en mouseUp probablemente debería solucionarlo.
Es bastante fácil:
anular la propiedad mouseDownCanMoveWindow
override var mouseDownCanMoveWindow:Bool {
return false
}
Funciona para mí después de DOS pasos:
- Subclase NSView, anule el
mouseDownCanMoveWindow
para devolver SÍ. - Subclase NSWindow, invalide
isMovableByWindowBackground
para devolver YES.
Si tiene un NSTableView
en su ventana, con la selección habilitada , la anulación de la propiedad mouseDownCanMoveWindow
no funcionará.
En su lugar, necesita crear una subclase NSTableView
y anular los siguientes eventos del mouse (y usar el performWindowDragWithEvent:
mencionado en la respuesta de Dimitri ):
@interface WindowDraggableTableView : NSTableView
@end
@implementation WindowDraggableTableView
{
BOOL _draggingWindow;
NSEvent *_mouseDownEvent;
}
- (void)mouseDown:(NSEvent *)event
{
if (self.window.movableByWindowBackground == NO) {
[super mouseDown:event]; // Normal behavior.
return;
}
_draggingWindow = NO;
_mouseDownEvent = event;
}
- (void)mouseDragged:(NSEvent *)event
{
if (self.window.movableByWindowBackground == NO) {
[super mouseDragged:event]; // Normal behavior.
return;
}
assert(_mouseDownEvent);
_draggingWindow = YES;
[self.window performWindowDragWithEvent:_mouseDownEvent];
}
- (void)mouseUp:(NSEvent *)event
{
if (self.window.movableByWindowBackground == NO) {
[super mouseUp:event]; // Normal behavior.
return;
}
if (_draggingWindow == YES) {
_draggingWindow = NO;
return; // Event already handled by `performWindowDragWithEvent`.
}
// Triggers regular table selection.
NSPoint locationInWindow = event.locationInWindow;
NSPoint locationInTable = [self convertPoint:locationInWindow fromView:nil];
NSInteger row = [self rowAtPoint:locationInTable];
if (row >= 0 && [self.delegate tableView:self shouldSelectRow:row])
{
NSIndexSet *rowIndex = [NSIndexSet indexSetWithIndex:row];
[self selectRowIndexes:rowIndex byExtendingSelection:NO];
}
}
@end
Tampoco olvide establecer la ventana correspondiente de la propiedad movableByWindowBackground
también:
self.window.movableByWindowBackground = YES;
mouseDownCanMoveWindow
solución mouseDownCanMoveWindow
( https://.com/a/4564146/901641 ) pero no me funcionó. Me deshice de ese método y en su lugar lo agregué a mi subclase de ventana:
- (BOOL)isMovableByWindowBackground {
return YES;
}
que funcionó a la perfección.