I am trying to implement drag drop in NSCollectionView
which will allow to re arrange cells in view. I have set the delegate and implemented below methods :
-(BOOL)collectionView:(NSCollectionView *)collectionView writeItemsAtIndexes:(NSIndexSet *)indexes toPasteboard:(NSPasteboard *)pasteboard {
NSLog(@"Write Items at indexes : %@", indexes);
return YES;
}
- (BOOL)collectionView:(NSCollectionView *)collectionView canDragItemsAtIndexes:(NSIndexSet *)indexes withEvent:(NSEvent *)event {
NSLog(@"Can Drag");
return YES;
}
- (BOOL)collectionView:(NSCollectionView *)collectionView acceptDrop:(id<NSDraggingInfo>)draggingInfo index:(NSInteger)index dropOperation:(NSCollectionViewDropOperation)dropOperation {
NSLog(@"Accept Drop");
return YES;
}
-(NSDragOperation)collectionView:(NSCollectionView *)collectionView validateDrop:(id<NSDraggingInfo>)draggingInfo proposedIndex:(NSInteger *)proposedDropIndex dropOperation:(NSCollectionViewDropOperation *)proposedDropOperation {
NSLog(@"Validate Drop");
return NSDragOperationMove;
}
I am not sure how to take this further. With this I can see that now I can drag around the individual Collection Item but how can I make the Drop
?
You have only implemented the delegate methods but there s no logic in some of the methods. For example to drag around a Collection Item I would add below logic :
-(BOOL)collectionView:(NSCollectionView *)collectionView writeItemsAtIndexes:(NSIndexSet *)indexes toPasteboard:(NSPasteboard *)pasteboard {
NSData *indexData = [NSKeyedArchiver archivedDataWithRootObject:indexes];
[pasteboard setDraggedTypes:@["my_drag_type_id"]];
[pasteboard setData:indexData forType"@"my_drag_type_id"];
// Here we temporarily store the index of the Cell,
// being dragged to pasteboard.
return YES;
}
- (BOOL)collectionView:(NSCollectionView *)collectionView acceptDrop:(id<NSDraggingInfo>)draggingInfo index:(NSInteger)index dropOperation:(NSCollectionViewDropOperation)dropOperation {
NSPasteboard *pBoard = [draggingInfo draggingPasteboard];
NSData *indexData = [pBoard dataForType:@"my_drag_type_id"];
NSIndexSet *indexes = [NSKeyedUnarchiver unarchiveObjectWithData:indexData];
NSInteger draggedCell = [indexes firstIndex];
// Now we know the Original Index (draggedCell) and the
// index of destination (index). Simply swap them in the collection view array.
return YES;
}
You also need to register the collection view to drag type in awakefromnib as
[_myCollectionView registerForDraggedTypes:@[@"my_drag_type_id"]];
And make sure that you have set the collection view as selectable.
In addition to what GoodSp33d mentions above, you're also missing the validate
delegate function which is required to accept drops. In Swift this is:
func collectionView(_ collectionView: NSCollectionView, validateDrop draggingInfo: NSDraggingInfo, proposedIndexPath proposedDropIndexPath: AutoreleasingUnsafeMutablePointer<NSIndexPath>, dropOperation proposedDropOperation: UnsafeMutablePointer<NSCollectionViewDropOperation>) -> NSDragOperation
Note the return value, NSDragOperation. This method should contain code that determines precisely what kind of drag operation is being attempted and returns this value. Returning the wrong thing can lead to some pretty annoying bugs.
Further note that in order to support this kind of operation, the collection view layout class you are using must also support drag and drop. Flow layout should do this out-of-the-box, but if you're using a custom layout you may need to adapt it to support drag-and-drop so that the collection view can detect valid drop targets and determine a suitable index path for them.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With