我有一个多节的tableview。在编辑模式下,我允许行从一个部分移动到另一个部分。从一个部分删除最后一行后,我删除该部分。所以我在moveRowAtIndexPath中使用deleteSection。
当从该部分移动最终项目时,部分标题将按计划消失。但是有一个非常奇怪的动画错误,其中移动的行似乎与上面删除的行“合并”,并且“to”部分底部显示一个空行(可能是因为该部分的numberOfRows是正确,但2行在同一位置)。更奇怪的是,当我点击此行的重新排序控件(不移动项目,只需触摸和释放)时,这两个项目“取消合并”。
我发布了一个video来证明这一点。
我已尝试包装我的数据更改并查看开始/结束更新中的更改,但无济于事。
我上传了一个测试项目here,我也会发布以下代码。几点:
代码(所有这些都在演示项目中):
我在loadView中设置了数组:
- (void)loadView{
array1 = [NSMutableArray array];
[array1 addObject:@"test 0"];
[array1 addObject:@"test 1"];
[array1 addObject:@"test 2"];
array2 = [NSMutableArray array];
[array2 addObject:@"test a"];
[array2 addObject:@"test b"];
[super loadView];
}
我还有一个方法可以返回这些数组的组合 - 这用作数据源:
- (NSMutableArray *)sourceArray{
NSMutableArray *result = [NSMutableArray array];
if (array1.count > 0) {
[result addObject:array1];
}
if (array2.count >0) {
[result addObject:array2];
}
return result;
}
允许非常简单的行/节数:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return self.sourceArray.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [[self.sourceArray objectAtIndex:section] count];
}
标准单元格/标题格式:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.textLabel.text = [[self.sourceArray objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
return cell;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [NSString stringWithFormat:@"Section %i", section];
}
这就是我做魔术的地方
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
NSMutableArray *fromArray = [self.sourceArray objectAtIndex:fromIndexPath.section];
NSMutableArray *toArray = [self.sourceArray objectAtIndex:toIndexPath.section];
NSString *movedObject = [[self.sourceArray objectAtIndex:fromIndexPath.section] objectAtIndex:fromIndexPath.row];
[fromArray removeObject:movedObject];
[toArray insertObject:movedObject atIndex:toIndexPath.row];
if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) {
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
}
}
答案 0 :(得分:3)
我注意到来自待删除部分的行是在您修饰订单控件之前消失的行。
我怀疑当tableview调用此数据源方法时,其状态仍处于执行移动的过程中,因此调用'deleteSections'将使表尝试删除您正在移动的行。这并不是一个合并,因为它以与节头相同的速度逐渐消失,而它下面的那个正在缩小以填补空间。
点击控件会导致表格视图重新调整,并意识到该行实际上并没有消失。
尝试解决此问题,尝试通过调度调用在下一个runloop中运行删除,如:
if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) {
dispatch_async(dispatch_get_main_queue(), ^() {
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
});
}
这将导致删除仍然在主线程上运行,但允许'moveRow'和它发生的任何调用堆栈在删除调用之前完成其逻辑
答案 1 :(得分:2)
您的问题出在动画中。一个正在完成,而另一个尚未完成(移动和删除动画),导致一个单元格被绘制在另一个单元格上。您可以通过再次移动单元格来验证这一点。然后会显示正确的顺序。根据Apple在UITableView上的docs:
注意:数据源不应该从tableView的实现中调用setEditing:animated::commitEditingStyle:forRowAtIndexPath:。如果由于某种原因必须使用performSelector:withObject:afterDelay:方法,它应该在延迟之后调用它。
因此要解决此问题,请执行以下操作:
if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) {
[self performSelector:@selector(someMethod:) withObject:fromIndexPath afterDelay:1.0];
}
- (void) someMethod:(NSIndexPath *) fromIndexPath {
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
}
应该可以正常工作。只需将延迟更改为适合您的延迟。
答案 2 :(得分:0)
如果您的行或其中的内容可以成为焦点,您是否检查过您已调用resignFirstResponder
或[view endEditing:YES]
?我们在使用文本字段时看到了这一点,并且(IIRC也依赖于iOS 4版本)将焦点留在了其中一个字段中。
答案 3 :(得分:0)
删除该部分后,您必须重新加载tableview。试试这段代码。
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
NSMutableArray *fromArray = [self.sourceArray objectAtIndex:fromIndexPath.section];
NSMutableArray *toArray = [self.sourceArray objectAtIndex:toIndexPath.section];
NSString *movedObject = [[self.sourceArray objectAtIndex:fromIndexPath.section] objectAtIndex:fromIndexPath.row];
[fromArray removeObject:movedObject];
[toArray insertObject:movedObject atIndex:toIndexPath.row];
if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) {
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView reloadData];
}
}
答案 4 :(得分:0)
在代码中交换fromArray
和toArray
的顺序。如果项目在从数组中删除之前保留计数为1,则在将其添加到toArray
之前,其保留计数为0。
如果您更换订单,该项目将从保留计数1到2,然后在删除完成后返回到1。
答案 5 :(得分:0)
我认为UITableViewRowAnimationFade动画干扰了UITableViewCell移动动画。您可以尝试的一件事是延迟部分删除有点迟,以便单元格移动行动画完成。
尝试使用以下代码替换您的代码。
-(void)deleteSection:(NSIndexSet*)indexSet
{
[self.tableView deleteSections:indexSet withRowAnimation:UITableViewRowAnimationFade];
}
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
NSMutableArray *fromArray = [self.sourceArray objectAtIndex:fromIndexPath.section];
NSMutableArray *toArray = [self.sourceArray objectAtIndex:toIndexPath.section];
NSString *movedObject = [[self.sourceArray objectAtIndex:fromIndexPath.section] objectAtIndex:fromIndexPath.row];
[fromArray removeObject:movedObject];
[toArray insertObject:movedObject atIndex:toIndexPath.row];
if ([self.tableView numberOfRowsInSection: fromIndexPath.section] == 0) {
[self performSelector:@selector(deleteSection:) withObject:[NSIndexSet indexSetWithIndex:fromIndexPath.section] afterDelay:1.0];
// [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:fromIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
}
}
答案 6 :(得分:0)
在最后一行丢失动画的解决方案:
if([listOfItemsOnTransaction count]==indexPath.row){
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]
withRowAnimation:UITableViewRowAnimationFade];
[self.tableView reloadData];
}else
{
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]
withRowAnimation:UITableViewRowAnimationFade];
}