【问题标题】:Animated reloadData on UITableViewUITableView 上的动画 reloadData
【发布时间】:2011-11-24 18:21:11
【问题描述】:

你会如何在UITableView 上动画- reloadData?数据源在UIFetchedResultsController,所以我无法使用– insertSections:withRowAnimation:– deleteSections:withRowAnimation: 包裹在– beginUpdates– endUpdates 中。

编辑: 我想在NSFetchedResultsController refetch 之后调用- reloadData

【问题讨论】:

标签: objective-c ios cocoa-touch uitableview


【解决方案1】:

您不能为reloadData 设置动画。您将不得不使用表格视图的insert...delete...move...reloadRows... 方法使其具有动画效果。

使用NSFetchedResultsController 时这非常简单。 NSFetchedResultsControllerDelegate 的文档包含一组示例方法,您只需适应自己的代码即可:

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView beginUpdates];
}


- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
    atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {

    switch(type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
                            withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
                             withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
    atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
    newIndexPath:(NSIndexPath *)newIndexPath {

    UITableView *tableView = self.tableView;

    switch(type) {

        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                       withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                       withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeUpdate:
            [self configureCell:[tableView cellForRowAtIndexPath:indexPath]
                  atIndexPath:indexPath];
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                       withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                       withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView endUpdates];
}

【讨论】:

  • 很抱歉,在NSFetchedResultsController“refetch”之后我没有提到我需要重新加载表数据。我认为,它可以用一些 CALayer 动画来完成 UITableView... 像重复的表视图层、重新获取、重新加载数据、关闭动画层...
【解决方案2】:

我做了分类方法。

- (void)reloadData:(BOOL)animated
{
    [self reloadData];

    if (animated) {

        CATransition *animation = [CATransition animation];
        [animation setType:kCATransitionPush];
        [animation setSubtype:kCATransitionFromBottom];
        [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
        [animation setFillMode:kCAFillModeBoth];
        [animation setDuration:.3];
        [[self layer] addAnimation:animation forKey:@"UITableViewReloadDataAnimationKey"];

    }
}

【讨论】:

  • 如果您需要一些自定义动画,这是一个不错的解决方案
  • 很棒的解决方案!我只有一件事要补充。在我的情况下,我遇到问题导致 TableView 在 reloadData 全部滚动到底部之前,所以当动画发生时,它搞砸了所有单元格和表格的框架。我可以解决它,确保在 reloadData 之前将 tableView 全部滚动到顶部:[self scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO];
  • 我可以避免,标题受到影响。现在,当我键入时,表头中有一个搜索栏。整个表格重新加载动画,包括我正在输入的文本。
  • 我发现 kCATransitionFade 看起来比 kCATransitionFromBottom 好得多。
  • 很好的解决方案,谢谢。小问题:为了代码的可读性,方法签名应该是reloadDataAnimated:(BOOL)animated
【解决方案3】:

您可以使用以下方法制作 reLoadData 的基本动画:

// Reload table with a slight animation
[UIView transitionWithView:tableViewReference 
                  duration:0.5f 
                   options:UIViewAnimationOptionTransitionCrossDissolve 
                animations:^(void) {
    [tableViewReference reloadData];
} completion:NULL];

【讨论】:

  • 在任何其他转换中,表格视图数据在您开始滚动之前不会重新加载。知道为什么吗?
  • 当您更新不在主流程中的表格时,表格可能不会自动更新。在这些情况下,您可以使用: [[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
  • 这会放在动画块中吗?
  • 没关系,反复试验表明它应该在过渡的完成块中。谢谢! :)
【解决方案4】:

我根据this link 的解决方案创建了一个UITableView 类别方法。

它应该重新加载所有表格部分。您可以使用UITableViewRowAnimation 选项来获得不同的动画效果。

- (void)reloadData:(BOOL)animated
{
    [self reloadData];

    if (animated)
    {
         [self reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.numberOfSections)] withRowAnimation:UITableViewRowAnimationBottom];
    }
}

【讨论】:

    【解决方案5】:
     typedef enum {
       UITableViewRowAnimationFade,
       UITableViewRowAnimationRight,
       UITableViewRowAnimationLeft,
       UITableViewRowAnimationTop,
       UITableViewRowAnimationBottom,
       UITableViewRowAnimationNone,
       UITableViewRowAnimationMiddle,
       UITableViewRowAnimationAutomatic = 100
    } UITableViewRowAnimation;
    

    以及方法:

       [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
    

    【讨论】:

      【解决方案6】:

      当您想用动画重新加载整个表格时,您可以简单地调用此行:

      NSRange range = NSMakeRange(0, [self numberOfSectionsInTableView:self.tableView]);
      NSIndexSet *sections = [NSIndexSet indexSetWithIndexesInRange:range];
      [self.tableView reloadSections:sections withRowAnimation:UITableViewRowAnimationFade];
      

      【讨论】:

      • 不错!正在寻找一个干净的解决方案,这是为那些不想调用粗暴的 reloadData ....
      【解决方案7】:

      您可能想使用:

      Objective-C

      /* Animate the table view reload */
      [UIView transitionWithView:self.tableView
                        duration:0.35f
                         options:UIViewAnimationOptionTransitionCrossDissolve
                      animations:^(void)
       {
            [self.tableView reloadData];
       }
                      completion:nil];
      

      斯威夫特

      UIView.transitionWithView(tableView,
                                duration:0.35,
                                options:.TransitionCrossDissolve,
                                animations:
      { () -> Void in
          self.tableView.reloadData()
      },
                                completion: nil);
      

      动画选项:

      TransitionNone TransitionFlipFromLeft TransitionFlipFromRight TransitionCurlUp TransitionCurlDown TransitionCrossDissolve TransitionFlipFromTop TransitionFlipFromBottom

      Reference

      【讨论】:

        【解决方案8】:

        Swift 5.1 版答案@user500 (https://stackoverflow.com/users/620297/user500)

        func reloadData(_ animated: Bool) {
            reloadData()
            guard animated else { return }
            let animation = CATransition()
            animation.type = .push
            animation.subtype = .fromBottom
            animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
            animation.fillMode = .both
            animation.duration = 0.3
            layer.add(animation, forKey: "UITableViewReloadDataAnimationKey")
        }
        

        【讨论】:

          猜你喜欢
          • 2013-01-12
          • 1970-01-01
          • 2019-06-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-17
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多