我刚刚在我的应用程序中遇到了我认为相同的问题。
情况是我有两个表部分。可以在部分内和部分之间拖动项目。用户可以将单元格拖动到第一部分中的任何行,但在第二部分中,项目已排序,因此对于任何给定单元格,只有一个有效行。
如果我滚动视图,使第 1 部分的底部和第 2 部分的顶部可见,则抓取第 1 部分中排序到第 2 部分底部的项目,然后将其拖到第 2 部分的顶部,我的tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:
方法被调用,我返回正确的目标位置,该位置位于屏幕底部下方的几行处。在 UI 中,您可以看到屏幕底部创建了一个空单元格,这不是正确的目标行。
当您放开单元格时,在屏幕底部(第 2 部分的中间)创建的虚假单元格会留在那里!tableView:cellForRowAtIndexPath:
甚至从来没有被要求这样做。一旦你尝试用该单元格做任何事情,你就会崩溃。
我的第一个解决方案是在末尾调用 [tableView reloadData]tableView:moveRowAtIndexPath:toIndexPath:
。但这会导致崩溃,所以我在延迟后间接调用它。但接下来还有anotherbug:延迟 reloadData 调用后,tableView:moveRowAtIndexPath:toIndexPath:
再次被调用,并发出虚假请求,将项目移动到第一部分末尾之后的同一位置。因此,我必须添加代码来忽略虚假的无操作请求。
所以,这是代码:
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)pathSrc toIndexPath:(NSIndexPath *)pathDst
{
// APPLE_BUG: after doing the delayed table reload (see below), we get a bogus
// request to move a nonexistant cell to its current location
if (pathSrc.row == pathDst.row && pathSrc.section == pathDst.section)
return;
// update your data model to reflect the move...
// APPLE_BUG: if you move a cell to a row that's off-screen (because the destination
// has been modified), the bogus cell gets created and eventually will cause a crash
[self performSelector:@selector(delayedReloadData:) withObject:tableView afterDelay:0];
}
- (void)delayedReloadData:(UITableView *)tableView
{
Assert(tableView == self.tableView);
[tableView reloadData];
}
请注意,仍然存在一个 UI 错误。在屏幕上,拖动的单元格会动画化为虚假的空单元格。在动画结束时,空单元格将使用该行的正确数据重新绘制,但细心的用户会注意到拖动的单元格被动画到错误的位置,然后立即变形为不同的单元格。
这绝对是一个愚蠢的用户界面。我考虑过将正确的目标行滚动到屏幕上,但如果我这样做,它将用第二部分填充屏幕,然后任何拖回到第一部分的尝试都会不断地被我的(现在烦人的)自动滚动所阻止。我可能必须更改 UI,但这需要对我的数据模型进行一些复杂且麻烦的更改。