注意:此問答描述的行爲現在可在OS X 10.9 Mavericks和更高版本的NSTableView中使用內置的API使用。請參閱NSTableViewDraggingDestinationFeedbackStyleGap。
如果在針對OS X 10.8或更低版本的應用程序中需要此行爲,此答案仍可能會有用。 原答案如下:
我已經實現了這一點。我的基本思路是這樣的:
@interface ORSGapOpeningTableView : NSTableView
@property (nonatomic) NSInteger dropTargetRow;
@property (nonatomic) CGFloat heightOfDraggedRows;
@end
@implementation ORSGapOpeningTableView
#pragma mark - Dragging
- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender
{
NSInteger oldDropTargetRow = self.dropTargetRow;
NSDragOperation result = [super draggingUpdated:sender];
CGFloat imageHeight = [[sender draggedImage] size].height;
self.heightOfDraggedRows = imageHeight;
NSMutableIndexSet *changedRows = [NSMutableIndexSet indexSet];
if (oldDropTargetRow > 0) [changedRows addIndex:oldDropTargetRow-1];
if (self.dropTargetRow > 0) [changedRows addIndex:self.dropTargetRow-1];
[self noteHeightOfRowsWithIndexesChanged:changedRows];
return result;
}
- (void)draggingExited:(id<NSDraggingInfo>)sender
{
self.dropTargetRow = -1;
[self noteHeightOfRowsWithIndexesChanged:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [self numberOfRows])]];
[super draggingExited:sender];
}
- (void)draggingEnded:(id<NSDraggingInfo>)sender
{
self.dropTargetRow = -1;
self.heightOfDraggedRows = 0.0;
self.draggedRows = nil;
[self noteHeightOfRowsWithIndexesChanged:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [self numberOfRows])]];
}
- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender
{
self.dropTargetRow = -1;
self.heightOfDraggedRows = 0.0;
self.draggedRows = nil;
[self noteHeightOfRowsWithIndexesChanged:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [self numberOfRows])]];
return [super performDragOperation:sender];
}
//在我的委託和數據源:
- (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id<NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)dropOperation
{
if (dropOperation == NSTableViewDropOn)
{
dropOperation = NSTableViewDropAbove;
[self.tableView setDropRow:++row dropOperation:dropOperation];
}
NSDragOperation result = [self.realDataSource tableView:tableView validateDrop:info proposedRow:row proposedDropOperation:dropOperation];
if (result != NSDragOperationNone)
{
self.tableView.dropTargetRow = row;
}
else
{
self.tableView.dropTargetRow = -1; // Don't open a gap
}
return result;
}
- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row
{
CGFloat result = [tableView rowHeight];
if (row == self.tableView.dropTargetRow - 1 && row > -1)
{
result += self.tableView.heightOfDraggedRows;
}
return result;
}
注意,這是簡化代碼,而不是逐字複製/粘貼從我的程序。實際上,我最終將其全部包含在使用代理委託和數據源對象的NSTableView子類中,因此上面的數據源/委託方法中的代碼實際上在代理攔截對真實委託和數據源的調用中。這樣,真正的數據源和委託人就不必做任何特殊的事情來獲得缺口開放行爲。另外,有時桌面視圖動畫會有一點片狀,這對於第一行之上的拖動不起作用(因爲沒有行可以更高,所以沒有間隙被打開)。總而言之,儘管還有進一步改進的空間,但這種方法工作得很好。
我仍然想嘗試類似的方法,但插入一個空行(如Caleb建議)而不是更改行高。
我想知道如何做到這一點! – Vervious 2012-04-13 17:40:42
我不確定這是否會起作用,但是如何在移動時插入空行? – lnafziger 2012-04-16 06:11:46
@Inafziger我也想到了,但我認爲「不幸的是,最好的我可以告訴,NSTableView不會在拖放過程中更新它的佈局」,這是行不通的。 – mydogisbox 2012-04-16 15:06:44