Пользовательский NSView Drag Destination

Я пытаюсь создать простой NSView, который позволит перетаскивать на него папку из Finder. Путь к папке - это единственное, что я хочу, чтобы представление принималось как перетаскиваемый элемент. Я пытался следовать документации Apple, но пока ничего не работает. До сих пор я только пытался заставить представление работать с любым типом файлов, но я даже не могу этого сделать. Вот что у меня так далеко:

-(id) initWithFrame:(NSRect)frameRect
{
    if (self = [super initWithFrame:frameRect])
    {
        NSLog(@"getting called");
        [self registerForDraggedTypes:[NSArray arrayWithObjects:NSPasteboardTypeString,
                                       NSPasteboardTypePDF,
                                       NSPasteboardTypeTIFF,
                                       NSPasteboardTypePNG,
                                       NSPasteboardTypeRTF,
                                       NSPasteboardTypeRTFD,
                                       NSPasteboardTypeHTML,
                                       NSPasteboardTypeTabularText,
                                       NSPasteboardTypeFont,
                                       NSPasteboardTypeRuler,
                                       NSPasteboardTypeColor,
                                       NSPasteboardTypeSound,
                                       NSPasteboardTypeMultipleTextSelection,
                                       NSPasteboardTypeFindPanelSearchOptions, nil]];
    }
    return self;
}

-(BOOL) prepareForDragOperation: (id<NSDraggingInfo>) sender
{
    NSLog(@"preparing for drag");

    return YES;
}

initWithFrame: метод вызывается, но когда я пытаюсь перетащить в представление prepareForDragOperation: метод никогда не вызывается. Мои вопросы:

  1. Что я делаю неправильно? Почему нет prepareForDragOperation: когда-нибудь звонили?
  2. Что мне нужно сделать, чтобы операция перетаскивания поддерживала только перетаскивание папок?

Обновить

Я обновил свой registerForDraggedTypes: метод с каждым типом, который я мог найти. Теперь это выглядит так:

[self registerForDraggedTypes:[NSArray arrayWithObjects:NSPasteboardTypeString,
                               NSPasteboardTypePDF,
                               NSPasteboardTypeTIFF,
                               NSPasteboardTypePNG,
                               NSPasteboardTypeRTF,
                               NSPasteboardTypeRTFD,
                               NSPasteboardTypeHTML,
                               NSPasteboardTypeTabularText,
                               NSPasteboardTypeFont,
                               NSPasteboardTypeRuler,
                               NSPasteboardTypeColor,
                               NSPasteboardTypeSound,
                               NSPasteboardTypeMultipleTextSelection,
                               NSPasteboardTypeFindPanelSearchOptions,
                               NSStringPboardType,
                               NSFilenamesPboardType,
                               NSPostScriptPboardType,
                               NSTIFFPboardType,
                               NSRTFPboardType,
                               NSTabularTextPboardType,
                               NSFontPboardType,
                               NSRulerPboardType,
                               NSFileContentsPboardType,
                               NSColorPboardType,
                               NSRTFDPboardType,
                               NSHTMLPboardType,
                               NSURLPboardType,
                               NSPDFPboardType,
                               NSVCardPboardType,
                               NSFilesPromisePboardType,
                               NSMultipleTextSelectionPboardType, nil]];

Я заметил, что prepareForDragOperation: метод не вызывается, когда я перетаскиваю папку в представление. Я пропустил шаг?

2 ответа

Решение

Вот простой маленький вид перетаскивания, соответствующий этим критериям:

MDDragDropView.h:

@interface MDDragDropView : NSView {
    BOOL        isHighlighted;
}

@property (assign, setter=setHighlighted:) BOOL isHighlighted;

@end

MDDragDropView.m:

@implementation MDDragDropView

@dynamic isHighlighted;

- (void)awakeFromNib {
    NSLog(@"[%@ %@]", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
    [self registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
}

- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender {
    NSLog(@"[%@ %@]", NSStringFromClass([self class]), NSStringFromSelector(_cmd));

    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];
    return YES;
}
- (BOOL)isHighlighted {
    return isHighlighted;
}

- (void)setHighlighted:(BOOL)value {
    isHighlighted = value;
    [self setNeedsDisplay:YES];
}

- (void)drawRect:(NSRect)dirtyRect {
    [super drawRect:dirtyRect];
    if (isHighlighted) {
        [NSBezierPath setDefaultLineWidth:6.0];
        [[NSColor keyboardFocusIndicatorColor] set];
        [NSBezierPath strokeRect:self.frame];
    }
}

@end

Причина prepareForDragOperation: не вызывается из-за того, что последовательность назначения перетаскивания следует за точным набором шагов, и если более ранние шаги не реализованы или не реализованы, но возвращают ответ типа "остановить операцию перетаскивания", более поздние методы никогда не достигаются, (В вашем случае не похоже, что вы реализовали draggingEntered: метод, который должен был бы вернуть что-то кроме NSDragOperationNone продолжить в последовательности).

До prepareForDragOperation: отправлено, представление сначала отправляется серией перетаскивающих сообщений назначения:

Один - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender,

В зависимости от NSDragOperation маска, возвращенная из этого метода, будет вызвана следующая, если она реализована в вашем классе:

множественный - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender,

В зависимости от NSDragOperation маска возвращается из этого метода, затем prepareForDragOperation: будет называться.

Я использую NSURLPboardType чтобы зарегистрироваться для удаления материалов из Finder (когда я перетаскиваю файл или папку в свое приложение, он получает их в виде URL) Попробуйте это. И если это сработает, это решит вашу вторую проблему: просто проверьте, является ли URL папкой для принятия, или отклоните удаление:

// if item is an NSURL * :
CFURLHasDirectoryPath((CFURLRef)item)
// returns true if item is the URL of a folder.
Другие вопросы по тегам