拖动交换NSView

时间:2016-08-05 10:45:03

标签: objective-c cocoa drag-and-drop

因为你永远不知道,它可能是有用的,我一直在尝试编写一个灵活的NSSplitView实验应用程序,其中可以以用户想要的任何方式即时添加和删除视图。我能做到这一点。

现在我认为能够:

是有用的
  1. 交换视图 - 例如,在四视图窗口中,左上角的视图可以拖到右下角,在释放鼠标按钮时,视图会相互交换。

  2. 拖出视图 - 例如,在四视图窗口中,如果左上方视图被拖出包含窗口,那么它将成为一个包含该视图的窗口,原始窗口将成为三个视图窗口。

  3. 拖入视图 - 以便可以将窗口拖入视图,关闭窗口并将其视图添加到拖动它的窗口中。

  4. 我已经编写了第一个程序(灵活设置拆分视图)https://github.com/HeadBanging/SplitViewTest,但我完全失去了如何做其余的事情 - 特别是第一点。

    如果您查看代码,您可以看到我已经开始(使用Apple和其他地方的教程),但它并没有做我想要的。有没有人有任何建议?

    当然,如果你需要的只是一个灵活的项目拆分窗口,那么你去 - 我的(上面的下载),没有使用限制 - 并且一切顺利。

    Willeke对如何使拖拽工作提出了一些很好的建议,我已经实现了如下(Git上的完整代码):

    #pragma mark Dragging
    
    - (NSImage *)imageRepresentationOfView:(NSView*)draggingView {
        BOOL wasHidden = draggingView.isHidden;
        CGFloat wantedLayer = draggingView.wantsLayer;
    
        draggingView.hidden = NO;
        draggingView.wantsLayer = YES;
    
        NSImage *image = [[NSImage alloc] initWithSize:draggingView.bounds.size];
        [image lockFocus];
        CGContextRef ctx = [NSGraphicsContext currentContext].graphicsPort;
        [draggingView.layer renderInContext:ctx];
        [image unlockFocus];
    
        draggingView.wantsLayer = wantedLayer;
        draggingView.hidden = wasHidden;
    
        return image;
    }
    
    - (void)mouseDown:(NSEvent *)theEvent {
        NSSize dragOffset = NSMakeSize(0.0, 0.0);
        NSPasteboard *pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
        [pboard declareTypes:[NSArray arrayWithObject:NSTIFFPboardType]  owner:self];
    
        DebugView *hitView;
        NSPoint startLocation = NSMakePoint(0, 0);
        NSImage *draggedImage;
        BOOL found = NO;
    
        fHitView = nil;
        while ((hitView = [[[self subviews] objectEnumerator] nextObject]) && !found) {
            if ([hitView isKindOfClass:[DebugView class]] && [(DebugView *)hitView dragEnabled]) { //Change DebugView to Draggable View, and use as container for plugin views
                draggedImage = [self imageRepresentationOfView:hitView];
                startLocation = hitView.frame.origin;
                found = YES;
            } 
        }
        if (draggedImage != nil) {
            [pboard setData:[draggedImage TIFFRepresentation] forType:NSTIFFPboardType];
    
            [self dragImage:draggedImage at:startLocation offset:dragOffset
                      event:theEvent pasteboard:pboard source:self slideBack:YES];
        }
        return;
    }
    
    - (void)setHighlighted:(BOOL)value {
        isHighlighted = value;
        [self setNeedsDisplay:YES];
    }
    
    - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender {
        NSPasteboard *pboard = [sender draggingPasteboard];
    
        if ([[pboard types] containsObject:NSFilenamesPboardType]) {
    
            NSArray *paths = [pboard propertyListForType:NSFilenamesPboardType];
            for (NSString *path in paths) {
                NSError *error = nil;
                NSString *utiType = [[NSWorkspace sharedWorkspace]
                                     typeOfFile:path error:&error];
                if (![[NSWorkspace sharedWorkspace]
                      type:utiType conformsToType:(id)kUTTypeFolder]) {
    
                    [self setHighlighted:NO];
                    return NSDragOperationNone;
                }
            }
        }
        [self setHighlighted:YES];
        return NSDragOperationEvery;
    }
    
    - (void)draggingExited:(id <NSDraggingInfo>)sender {
        [self setHighlighted:NO];
    }
    
    - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender  {
        return YES;
    }
    
    - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender {
        [self setHighlighted:NO];
    
        DebugView *hitView;
        BOOL found = NO;
    
        fHitView = nil;
        while ((hitView = [[[self subviews] objectEnumerator] nextObject]) && !found) {
            if ([hitView isKindOfClass:[DebugView class]] && [(DebugView *)hitView dragEnabled]) {
                found = YES;
            }
        }
        NSView* tempView = [sender draggingSource];
        [[[sender draggingSource] superview] replaceSubview:[sender draggingSource] with:hitView];
    
        [self replaceSubview:hitView with:tempView];
        [self setNeedsDisplay:YES];
        [[[sender draggingSource] superview] setNeedsDisplay:YES];
        return YES;
    }
    
    - (BOOL)isHighlighted {
        return isHighlighted;
    }
    

    下降部分部分有效 - 有时候视图准备接受掉落,有时候它没有(任何人看到我做错了什么? - 它应该一直有效,除非被放入的视图是源视图)。

    最后一块拼图对我来说仍然是一个谜(接受掉落,并交换视图)。任何提示都将非常感激地接受。

1 个答案:

答案 0 :(得分:1)

视图可以有一个超级视图,当您将视图添加到另一个超级视图时,它将从原始超级视图中删除。用视图B替换视图A然后用视图A替换视图B是行不通的,因为视图B已经从其原始超视图中删除了。

Autolayout对我来说仍然是一个谜,但首先删除两个视图然后再添加它们似乎都有效:

- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender {
    [self setHighlighted:NO];

    // swap subviews of view1 and view2
    NSView *view1 = self;
    NSView *view2 = [sender draggingSource];

    // find subviews
    DebugView *hitView1, *hitView2;
    for (hitView1 in [view1 subviews]) {
        if ([hitView1 isKindOfClass:[DebugView class]]) {
            break;
        }
    }
    for (hitView2 in [view2 subviews]) {
        if ([hitView2 isKindOfClass:[DebugView class]]) {
            break;
        }
    }

    // swap hitView1 and hitView2
    if (hitView1 && hitView2) {
        [hitView1 removeFromSuperview];
        [hitView2 removeFromSuperview];
        [view1 addSubview:hitView2];
        NSDictionary *views = NSDictionaryOfVariableBindings(hitView2);
        [view1 addConstraints:
            [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[hitView2]|"
                                                    options:0
                                                    metrics:nil
                                                      views:views]];
        [view1 addConstraints:
            [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[hitView2]|"
                                                    options:0
                                                    metrics:nil
                                                      views:views]];
        [view2 addSubview:hitView1];
        views = NSDictionaryOfVariableBindings(hitView1);
        [view2 addConstraints:
            [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[hitView1]|"
                                                    options:0
                                                    metrics:nil
                                                      views:views]];
        [view2 addConstraints:
            [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[hitView1]|"
                                                    options:0
                                                    metrics:nil
                                                      views:views]];
        return YES;
    }
    return NO;
}