如何在拖拽NSCollectionView项时实现交互式重排?
NSCollectionView实现拖拽时交互式移开现有项的方法
像Preview这类应用会在拖拽操作时通过交互式地移开现有项来指示放置位置,效果为拖拽过程中周围的项自动腾出空间以展示放置位置。
据我回忆(IIRC),这也是所有标准布局下UICollectionView的默认行为。相比之下,NSCollectionView仅会显示插入指示器,不会重新排列项,我始终无法找到实现上述效果的方法。有趣的是,另一篇问题的截图显示了我想要的效果,但讨论内容并不相关。
当前拖拽代理设置代码
- (BOOL)collectionView:(NSCollectionView *)collectionView canDragItemsAtIndexPaths:(NSSet<NSIndexPath *> *)indexPaths withEvent:(NSEvent *)event { return YES; } - (id<NSPasteboardWriting>)collectionView:(NSCollectionView *)collectionView pasteboardWriterForItemAtIndexPath:(NSIndexPath *)indexPath { NSPasteboardItem *pasteboardItem = [[NSPasteboardItem alloc] init]; [pasteboardItem setString:@"Whatever is fine" forType:NSPasteboardTypeString]; return pasteboardItem; } - (NSDragOperation)collectionView:(NSCollectionView *)collectionView validateDrop:(id<NSDraggingInfo>)draggingInfo proposedIndexPath:(NSIndexPath * _Nonnull __autoreleasing *)proposedDropIndexPath dropOperation:(NSCollectionViewDropOperation *)proposedDropOperation { *proposedDropOperation = NSCollectionViewDropBefore; return NSDragOperationMove; }
我原本以为布局的-layoutAttributesForDropTargetAtPoint:/-layoutAttributesForInterItemGapBeforeIndexPath:方法是用于实现该效果的,但实际上它们仅用于设置指示器位置,不会影响项的排列。
例如在子类化的NSCollectionViewFlowLayout中设置任意矩形:
- (NSCollectionViewLayoutAttributes *)layoutAttributesForDropTargetAtPoint:(NSPoint)pointInCollectionView { NSCollectionViewLayoutAttributes *attributes = [[super layoutAttributesForDropTargetAtPoint:pointInCollectionView] copy]; attributes.frame = NSMakeRect(60, 0, 200, 200); return attributes; }
这段代码只会将指示器渲染在{60, 0}位置,但不会对项的排列产生任何影响。
我当然可以进一步扩展布局使其感知拖拽会话,但这感觉像是一种取巧方案;而且在拖拽期间手动使布局失效(更不用说通过-performBatchUpdates:completionHandler:触发动画响应),无疑印证了这一点。另一种方法是直接操作项的frame,但这也像是在与NSCollectionView的设计逻辑对抗,而非利用其特性。
鉴于这种交互模式应用广泛,肯定存在无需取巧的正确实现方式。我忽略了什么?谢谢。
内容的提问来源于stack exchange,提问作者K Lee
相关产品推荐
相关产品推荐

