【问题标题】:How to detect that animation has ended on UITableView beginUpdates/endUpdates?如何在 UITableView beginUpdates/endUpdates 上检测到动画已经结束?
【发布时间】:2011-11-29 05:47:20
【问题描述】:

我使用 insertRowsAtIndexPaths/deleteRowsAtIndexPaths 包裹在 beginUpdates/endUpdates 中插入/删除表格单元格。调整 rowHeight 时,我也在使用 beginUpdates/endUpdates。默认情况下,所有这些操作都是动画的。

使用beginUpdates/endUpdates时如何检测动画已经结束?

【问题讨论】:

  • 仅供参考:这也适用于-scrollToRowAtIndexPath:atScrollPosition:animated:

标签: iphone objective-c ios ipad


【解决方案1】:

您可以使用tableView:willDisplayCell:forRowAtIndexPath: 喜欢:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"tableView willDisplay Cell");
    cell.backgroundColor = [UIColor colorWithWhite:((indexPath.row % 2) ? 0.25 : 0) alpha:0.70];
}

但是,当表格中已经存在的单元格从屏幕外移到屏幕上时,它也会被调用,因此它可能不是您要查找的内容。我只是查看了所有 UITableViewUIScrollView 委托方法,在插入单元格动画后似乎没有任何处理。


为什么不直接在endUpdates之后动画结束时调用你想调用的方法呢?

- (void)setDownloadedImage:(NSMutableDictionary *)d {
    NSIndexPath *indexPath = (NSIndexPath *)[d objectForKey:@"IndexPath"];
    [indexPathDelayed addObject:indexPath];
    if (!([table isDragging] || [table isDecelerating])) {
        [table beginUpdates];
        [table insertRowsAtIndexPaths:indexPathDelayed withRowAnimation:UITableViewRowAnimationFade];
        [table endUpdates];
        // --> Call Method Here <--
        loadingView.hidden = YES;
        [indexPathDelayed removeAllObjects];
    }
}

【讨论】:

  • 谢谢,chown。不要认为willDisplayCell 会起作用。我需要它在动画之后发生,因为我需要在一切都解决之后进行视觉更新。
  • np @pixelfreak,如果我想到任何其他方法,我会告诉你的。
【解决方案2】:

尚未找到好的解决方案(缺少子类化 UITableView)。我决定暂时使用performSelector:withObject:afterDelay:。不理想,但可以完成工作。

更新:看起来我可以为此目的使用scrollViewDidEndScrollingAnimation:(这是特定于我的实现,请参阅评论)。

【讨论】:

  • scrollViewDidEndScrollingAnimation 仅在响应setContentOffsetscrollRectToVisible 时被调用
  • @samvermette 好吧,在我的例子中,当 beginUpdates/endUpdates 被调用时,UITableView 总是动画滚动。但这是特定于我的实现的,所以我同意这不是最好的答案,但它对我有用。
  • 似乎可以将更新包含在 UIView 动画块中。请参阅下面的答案:stackoverflow.com/a/14305039/634940.
【解决方案3】:

一个可能的解决方案是从您调用 endUpdates 的 UITableView 继承并覆盖其 setContentSizeMethod,因为 UITableView 会调整其内容大小以匹配添加或删除的行。这种方法也应该适用于reloadData

为确保仅在调用endUpdates 后才发送通知,还可以覆盖endUpdates 并在那里设置一个标志。

// somewhere in header
@private BOOL endUpdatesWasCalled_;

-------------------

// in implementation file

- (void)endUpdates {
    [super endUpdates];
    endUpdatesWasCalled_ = YES;
}

- (void)setContentSize:(CGSize)contentSize {
    [super setContentSize:contentSize];

    if (endUpdatesWasCalled_) {
        [self notifyEndUpdatesFinished];
        endUpdatesWasCalled_ = NO;
    }
}

【讨论】:

    【解决方案4】:

    这个怎么样?

    [CATransaction begin];
    
    [CATransaction setCompletionBlock:^{
        // animation has finished
    }];
    
    [tableView beginUpdates];
    // do some work
    [tableView endUpdates];
    
    [CATransaction commit];
    

    这是因为 tableView 动画在内部使用 CALayer 动画。也就是说,他们将动画添加到任何打开的CATransaction。如果不存在打开的CATransaction(正常情况),则隐式开始一个,在当前运行循环结束时结束。但是,如果您自己开始一个,就像这里所做的那样,那么它将使用那个。

    【讨论】:

    • 对我不起作用。动画仍在运行时调用完成块。
    • @MrVincenzo 您是否像在 sn-p 中一样在 beginUpdatesendUpdates 之前设置了 completionBlock
    • [CATransaction commit] 应该在 [tableView endUpdates] 之后而不是之前调用。
    • 如果单元格包含带有动画的视图,即 UIActivityIndi​​catorView,则永远不会调用完成块。
    • 这么久以来我从来不知道这一点。纯金 !!没有什么比看到一个漂亮的动画被 tableView.reloadData() 的必要邪恶杀死更糟糕的了。
    【解决方案5】:

    您可以像这样将您的操作包含在 UIView 动画块中:

    - (void)tableView:(UITableView *)tableView performOperation:(void(^)())operation completion:(void(^)(BOOL finished))completion
    {
        [UIView animateWithDuration:0.0 animations:^{
    
            [tableView beginUpdates];
            if (operation)
                operation();
            [tableView endUpdates];
    
        } completion:^(BOOL finished) {
    
            if (completion)
                completion(finished);
        }];
    }
    

    感谢https://stackoverflow.com/a/12905114/634940

    【讨论】:

    • 这段代码对我不起作用。在 endUpdates 之后,但在动画完成之前调用了完成块。
    • 这不起作用。应用此示例时,tableview 动画停止工作。
    • 尝试延长持续时间(如 0.3 秒) - 它应该可以工作(对我有用)
    【解决方案6】:

    斯威夫特版本


    CATransaction.begin()
    
    CATransaction.setCompletionBlock({
        do.something()
    })
    
    tableView.beginUpdates()
    tableView.endUpdates()
    
    CATransaction.commit()
    

    【讨论】:

      【解决方案7】:

      如果您的目标是 iOS 11 及更高版本,则应改用 UITableView.performBatchUpdates(_:completion:)

      tableView.performBatchUpdates({
          // delete some cells
          // insert some cells
      }, completion: { finished in
          // animation complete
      })
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-08-18
        • 2012-05-19
        • 1970-01-01
        • 2016-03-19
        • 2014-12-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多