【问题标题】:NSOutlineView drag&drop (next to an item) doesn't work for complex itemsNSOutlineView 拖放(在项目旁边)不适用于复杂项目
【发布时间】:2018-07-11 17:03:39
【问题描述】:

我的基本示例适用于由标准 ObjC 类表示的项目。 请参阅下面示例中 self.list 的初始化:

- (void) updateViews;
{
    NSDictionary *firstParent = [NSDictionary dictionaryWithObjectsAndKeys:@"Foo",@"parent",[NSArray arrayWithObjects:@"Foox",@"Fooz", nil],@"children", nil];
    NSDictionary *secondParent = [NSDictionary dictionaryWithObjectsAndKeys:@"Bar",@"parent",[NSArray arrayWithObjects:@"Barx",@"Barz", nil],@"children", nil];
    self.list = [NSArray arrayWithObjects:firstParent,secondParent, nil];

    self.outlineView.delegate = self;
    self.outlineView.dataSource = self;


    // Enable Drag and Drop
    [self.outlineView registerForDraggedTypes:@[LOCAL_REORDER_PASTEBOARD_TYPE]];
}


#pragma mark - NSOutlineViewDelegate

- (BOOL) outlineView:(NSOutlineView*)outlineView isItemExpandable:(id)item
{
    if ([item isKindOfClass:[NSDictionary class]]) {
        return YES;
    }
    else {
        return NO;
    }
}

- (NSInteger) outlineView:(NSOutlineView*)outlineView numberOfChildrenOfItem:(id)item
{
    if (item == nil) { //item is nil when the outline view wants to inquire for root level items
        return [self.list count];
    }

    if ([item isKindOfClass:[NSDictionary class]]) {
        return [[item objectForKey:@"children"] count];
    }

    return 0;
}

- (id) outlineView:(NSOutlineView*)outlineView child:(NSInteger)index ofItem:(id)item
{
    if (item == nil) { //item is nil when the outline view wants to inquire for root level items
        return [self.list objectAtIndex:index];
    }

    if ([item isKindOfClass:[NSDictionary class]]) {
        return [[item objectForKey:@"children"] objectAtIndex:index];
    }

    return nil;
}

- (NSView*) outlineView:(NSOutlineView*)outlineView viewForTableColumn:(NSTableColumn*)tableColumn item:(id)item
{
    NSTableCellView *result = [outlineView makeViewWithIdentifier:@"DataCell" owner:self];

    NSString *txt = nil;
    if ([item isKindOfClass:[NSDictionary class]]) {
        txt = [item objectForKey:@"parent"];//[NSString stringWithFormat:@"%i kids", [[item objectForKey:@"children"] count]];
    }
    else {
        txt = str(item);
    }

    result.textField.stringValue = txt;
    return result;
}

- (BOOL) outlineView:(NSOutlineView*)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pasteboard 
{
    [pasteboard declareTypes:[NSArray arrayWithObject:LOCAL_REORDER_PASTEBOARD_TYPE] owner:self];
    [pasteboard setData:[@"just a test - not yet implemented" dataUsingEncoding:NSUTF8StringEncoding] forType:LOCAL_REORDER_PASTEBOARD_TYPE];
    return YES;
}

- (NSDragOperation) outlineView:(NSOutlineView*)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index 
{
    NSUInteger op = NSDragOperationNone;
    if (index != NSOutlineViewDropOnItemIndex){
        op = NSDragOperationMove;
    }
    return op;
}

拖放按预期工作。

一旦我修改了child:(NSInteger)index ofItem:(id)item 方法以返回我自己的类的复杂项目,特别是TreeItem,那么拖放只允许:

  1. 放在物品上

  1. 放在父项旁边

但是第一张图片中显示的叶子项目旁边的下拉是不可能的。有什么线索吗?

让我也添加不工作的复杂项目的示例代码。 Storyboard 和 dragDrop 代码在这两种情况下是相同的。

#define LOCAL_REORDER_PASTEBOARD_TYPE @"LOCAL_REORDER_PASTEBOARD_TYPE"
#define str(...) [@[__VA_ARGS__] componentsJoinedByString:@""]

@interface TreeItem : NSObject
@property (nonatomic) NSArray<TreeItem*> *children;
@property (nonatomic) NSString *name;
+ (nonnull instancetype) itemWithName:(nonnull NSString*)name;
@end

@implementation TreeItem
+ (nonnull instancetype) itemWithName:(nonnull NSString*)name;
{
    TreeItem *obj = [[self alloc] init];
    obj.name = name;
    return obj;
}
- (NSArray<TreeItem*>*) children;
{
    return self.name.length > 3 ? nil : @[
        [TreeItem itemWithName:str(self.name, @"x")],
        [TreeItem itemWithName:str(self.name, @"z")],
    ];
}
@end

@interface SampleVC ()
@property (weak) IBOutlet NSOutlineView *outlineView;
@property (strong) NSArray<TreeItem*> *treeList;
@end

@implementation SampleVC

- (void) updateViews;
{
    self.treeList = @[
        [TreeItem itemWithName:@"Foo"],
        [TreeItem itemWithName:@"Bar"],
    ];
    self.outlineView.delegate = self;
    self.outlineView.dataSource = self;
    [self.outlineView reloadData];
    [self.outlineView registerForDraggedTypes:@[LOCAL_REORDER_PASTEBOARD_TYPE]];
}

- (BOOL) outlineView:(NSOutlineView*)outlineView isItemExpandable:(id)item
{
    return item == nil ? YES : ((TreeItem*)item).children != nil;
}

- (NSInteger) outlineView:(NSOutlineView*)outlineView numberOfChildrenOfItem:(id)item
{
    return item == nil ? self.treeList.count : (((TreeItem*)item).children != nil ? ((TreeItem*)item).children.count : 0);
}

- (id) outlineView:(NSOutlineView*)outlineView child:(NSInteger)index ofItem:(id)item
{
    return item == nil ? [self.treeList objectAtIndex:index] : ((TreeItem*)item).children[index];
}

- (NSView*) outlineView:(NSOutlineView*)outlineView viewForTableColumn:(NSTableColumn*)tableColumn item:(id)item
{
    NSTableCellView *result = [outlineView makeViewWithIdentifier:@"DataCell" owner:self];
    result.textField.stringValue = ((TreeItem*)item).name;
    return result;
}
@end

【问题讨论】:

    标签: objective-c xcode drag-and-drop nsoutlineview


    【解决方案1】:

    大纲视图找不到子元素所在的行,在视图顶部绘制下拉指示器。如果每次调用 - (NSArray&lt;TreeItem*&gt;*) children;TreeItem 返回一个新的 TreeItems 数组,NSOutlineViewrowForItem: 将无法工作。

    【讨论】:

    • 哇,我永远找不到自己。谢谢!
    • 哦,我也找了好几个小时。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-23
    • 2021-11-08
    • 2013-06-15
    • 2017-04-08
    • 1970-01-01
    • 2016-12-07
    • 1970-01-01
    相关资源
    最近更新 更多