我想使用iOS 5的漂亮的行移动调用来为tableview设置动画以匹配某些模型状态更改,而不是旧式的delete-and-insert。
更改可能包括重新排序和就地更新,我想对两者进行动画处理,因此某些行需要reloadRowsAtIndexPaths
。
但是!如果更新的单元格由于移动而移位,则UITableView
在存在移动时处理行重新加载似乎是完全错误的。使用较旧的delete + insert调用,应该是等效的,可以正常工作。
这里有一些代码;我为冗长而道歉,但它确实编译并运行。肉是doMoves:
方法。博览会如下。
#define THISWORKS
@implementation ScrambledList // extends UITableViewController
{
NSMutableArray *model;
}
- (void)viewDidLoad
{
[super viewDidLoad];
model = [NSMutableArray arrayWithObjects:
@"zero",
@"one",
@"two",
@"three",
@"four",
nil];
[self.navigationItem setRightBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:
#ifdef THISWORKS
@"\U0001F603"
#else
@"\U0001F4A9"
#endif
style:UIBarButtonItemStylePlain
target:self
action:@selector(doMoves:)]];
}
-(IBAction)doMoves:(id)sender
{
int fromrow = 4, torow = 0, changedrow = 2; // 2 = its "before" position, just like the docs say.
// some model changes happen...
[model replaceObjectAtIndex:changedrow
withObject:[[model objectAtIndex:changedrow] stringByAppendingString:@"\u2032"]];
id tmp = [model objectAtIndex:fromrow];
[model removeObjectAtIndex:fromrow];
[model insertObject:tmp atIndex:torow];
// then we tell the table view what they were
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:changedrow inSection:0]]
withRowAnimation:UITableViewRowAnimationRight]; // again, index for the "before" state; the tableview should figure out it really wants row 3 when the time comes
#ifdef THISWORKS
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:fromrow inSection:0]]
withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:torow inSection:0]]
withRowAnimation:UITableViewRowAnimationAutomatic];
#else // but this doesn't
[self.tableView moveRowAtIndexPath:[NSIndexPath indexPathForRow:fromrow inSection:0]
toIndexPath:[NSIndexPath indexPathForRow:torow inSection:0]];
#endif
[self.tableView endUpdates];
}
#pragma mark - Table view data source boilerplate, not very interesting
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return model.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@""];
if (cell == nil)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@""];
[cell.textLabel setText:[[model objectAtIndex:indexPath.row] description]];
[cell.detailTextLabel setText:[NSString stringWithFormat:@"this cell was provided for row %d", indexPath.row]];
return cell;
}
代码的作用:设置一个小模型(小型可变数组);当按下按钮时,它会对列表的中间元素进行小的更改,并将最后一个元素移动到第一个元素。然后它更新表视图以反映这些更改:重新加载中间行,删除最后一行并插入新的零行。
这很有效。事实上,向cellForRowAtIndexPath
添加日志记录表明,虽然我要求重新加载第2行,但是tableview正确地要求第3行,因为在实际进行更新时需要插入第3行。好哇!
现在注释掉顶部的#ifdef来代替使用moveRowAtIndexPath。
现在tableview 删除第2行,请求新行 2 (错误!),并将其插入最后的第2行位置(也是错误的!) 。最终结果是第1行向下移动了两个插槽而不是一个,并在屏幕外滚动以强制重新加载显示它与模型的不同步。我能理解moveRowAtIndexPath
是否以不同的顺序更改了tableview的私人模型,需要使用" new"而不是" old"重新加载或模型提取中的索引路径,但这不是正在发生的事情。请注意,在第二个"之后" pic,第三行和第四行的顺序相反,无论我重新加载哪个单元格都应该发生。
我的词汇量变得越来越多,诅咒苹果。我应该诅咒自己吗?行移动是否与同一更新块中的行重新加载明显不兼容(以及我怀疑,插入和删除)?在我提交错误报告之前,有人可以启发我吗?
答案 0 :(得分:3)
我只是花了一些时间玩你的代码,我同意;看起来它只是不起作用。
整个区域有点记录不足,但他们实际上并没有说你可以将moveRowAtIndexPath:toIndexPath:
与重载方法混合在一起。 表示它可以与行插入和行删除方法混合使用。如果我修改你的代码来代替它们,那些似乎是有效的。所以,你可能会要求增强,而不是提交错误。无论哪种方式,我肯定会将它发送到雷达。