繁体   English   中英

将最后一行移出节并删除节时出现奇怪的动画

[英]Strange animation when moving last row out of section and deleting section

我有一个多部分的tableview。 在编辑模式下,我允许将行从一个部分移到另一部分。 将最后一行从一个部分中删除后,我将删除该部分。 所以我在moveRowAtIndexPath内部使用deleteSection。

当最后一个项目从节中移出时,节标题将按计划消失。 但是有一个非常奇怪的动画错误,其中移动的行似乎与它上方的行“合并”,并且在“ to”部分的底部显示一个空行(可能是因为该部分的numberOfRows为正确,但2行位于同一位置)。 甚至更陌生,当我单击该行的重新排序控件(不移动项目,只需触摸并释放)时,两个项目“合并”。

我发布了一个视频来演示这一点。

我尝试包装我的数据更改并在开始/结束更新中查看更改,但无济于事。

我已经在这里上传了一个测试项目,我还将在下面发布代码。 要点:

  • 我试图在演示项目中复制数据源的格式,以防出现问题。 关键是我的源代码是其他两个数组的组合数组(尽管我看不到为什么会是个问题)。
  • 若要查看问题的行为,请将底部的两行向上移动到顶部。 但是不要将它们放在顶部的最后一行中,因为这似乎可以正常工作。
  • 在本演示项目中,将行从顶部移动到底部的另一种方式是错误的。

代码(所有这些都在演示项目中):

我在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];
        }
    }

我注意到,来自待删除部分的行将消失,直到您修改订单控件。

我怀疑当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'及其碰巧发生的任何调用栈在删除调用之前完成其逻辑

您的问题出在动画上。 一个正在完成而另一个尚未完成(移动和删除动画),导致一个单元格被绘制在另一个单元格上。 您可以通过再次移动单元格来验证这一点。 然后将显示正确的顺序。 根据Apple在UITableView上的文档

注意:数据源不应在tableView:commitEditingStyle:forRowAtIndexPath:的实现中调用setEditing:animated:。 如果出于某种原因,它必须在延迟后通过使用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];
}

应该工作正常。 只需将延迟更改为更适合您的时间即可。

我认为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];
    }
}

在最后一行丢失动画的解决方案:

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];


   }

如果行或行中的内容可以引起焦点,您是否检查过是否调用过resignFirstResponder[view endEditing:YES] 我们在使用文本字段时看到了这一点,并且(IIRC也依赖于iOS 4版本)将焦点放在其中一个字段上。

删除该部分后,您必须重新加载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];
        }

    }

在代码中交换fromArraytoArray的顺序。 如果该项目从数组中取出具有现有的1一个保留计数,它将具有其添加到之前一个保留的0计数toArray

如果您交换订单,则该项目将从保留计数1变为2,然后在删除完成后返回1。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM