【问题标题】:Drag swap NSViews拖动交换 NSViews
【发布时间】:2016-08-05 10:45:03
【问题描述】:

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

现在我认为能够:

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

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

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

我已经编写了一个程序来处理第一个问题(灵活设置拆分视图)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;
}

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

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

【问题讨论】:

  • 我建议阅读Drag and Drop Programming Topics。使用dragImage:at:offset:event:pasteboard:source:slideBack:NSDraggingSourceNSDraggingDestination
  • …即使我想要做的是拖动整个 NSView、按钮、小部件和所有内容,而不仅仅是一个 NSImage?正如我所说,我一直在关注教程(您甚至可能已经识别出一些代码来自教程!)但它似乎不起作用!
  • 拖动的图像是数据的表示,数据可以是任何东西:文本sn-p,文件,图像,表格行,url,...。
  • 啊。谢谢 - 我现在有了工作拖放的第一道曙光。至少,拖动位有效 - 但下降位没有那么多。下一步去哪里有什么好的提示吗?我还修复了代码的 GitHub,使其不再是 zip。
  • drop bit 也可以,交换performDragOperation中的视图。

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


【解决方案1】:

一个视图可以有一个超级视图,当您将一个视图添加到另一个超级视图时,它会从原始超级视图中删除。用视图 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;
}

【讨论】:

  • 你是一个绝对的传奇!非常感谢您对这个问题的帮助!
猜你喜欢
  • 1970-01-01
  • 2021-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
相关资源
最近更新 更多