目标c-拖动交换NSViews



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

现在我认为能够:是有用的

  1. 交换视图-例如,在四视图窗口中,左上角的视图可以拖动到右下角,松开鼠标按钮后,视图可以相互交换。

  2. 拖出视图-例如,在四视图窗口中,如果左上角的视图被拖出其包含的窗口,则它将成为包含该视图的右侧窗口,而原始窗口将成为三视图窗口。

  3. 在中拖动视图-这样可以将窗口拖动到视图中,关闭窗口并将其视图添加到拖动到的窗口中。

我已经编写了一个程序来完成第一部分(灵活设置拆分视图(https://github.com/HeadBanging/SplitViewTest但我完全不知道如何做剩下的事情,尤其是第一点。

如果你看一下代码,你会发现我已经开始了(使用苹果和其他地方的教程(,但它并没有达到我想要的效果。有人有什么建议吗?

当然,如果你所需要的只是为你的项目提供一个灵活的拆分窗口,那么就来吧——有我的(上面下载(,没有使用限制——一切都好。

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;
}

拖放部分部分起作用-有些时候视图准备接受拖放,有些时候它不起作用(有人看到我做错了什么吗?-它应该一直起作用,除非被拖放到的视图是源视图(。

谜题的最后一块对我来说仍然是个谜(接受掉落,并交换观点(。如有任何提示,我们将不胜感激。

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

自动布局对我来说仍然是个谜,但首先删除这两个视图,然后添加它们似乎都有效:

- (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;
}

最新更新