199

我有一个 UITableView 有两种模式。当我们在模式之间切换时,我有不同数量的部分和每个部分的单元格。理想情况下,当表格增长或缩小时,它会做一些很酷的动画。

这是我尝试过的代码,但它什么也没做:

CGContextRef context = UIGraphicsGetCurrentContext(); 
[UIView beginAnimations:nil context:context]; 
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; 
[UIView setAnimationDuration:0.5]; 

[self.tableView reloadData];
[UIView commitAnimations];

关于我如何做到这一点的任何想法?

4

17 回答 17

406

其实很简单:

[_tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];

文档中

调用此方法会使表视图向其数据源询问指定部分的新单元格。表格视图动画插入新单元格,因为它动画旧单元格。

于 2011-09-23T12:24:23.743 回答
290

您可能想使用:

Objective-C

[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);

斯威夫特 3、4 和 5

UIView.transition(with: tableView,
                  duration: 0.35,
                  options: .transitionCrossDissolve,
                  animations: { self.tableView.reloadData() }) // left out the unnecessary syntax in the completion block and the optional completion parameter

没有麻烦。:D

您还可以使用任何UIViewAnimationOptionTransitions您想要的更酷的效果:

  • transitionNone
  • transitionFlipFromLeft
  • transitionFlipFromRight
  • transitionCurlUp
  • transitionCurlDown
  • transitionCrossDissolve
  • transitionFlipFromTop
  • transitionFlipFromBottom
于 2012-11-07T00:45:16.040 回答
83

CATransition使用类有更多的自由。

它不仅限于褪色,还可以做运动。


例如:

(别忘了导入QuartzCore

CATransition *transition = [CATransition animation];
transition.type = kCATransitionPush;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.fillMode = kCAFillModeForwards;
transition.duration = 0.5;
transition.subtype = kCATransitionFromBottom;

[[self.tableView layer] addAnimation:transition forKey:@"UITableViewReloadDataAnimationKey"];

更改type以符合您的需求,例如kCATransitionFade等。

在 Swift 中的实现:

let transition = CATransition()
transition.type = kCATransitionPush
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.fillMode = kCAFillModeForwards
transition.duration = 0.5
transition.subtype = kCATransitionFromTop
self.tableView.layer.addAnimation(transition, forKey: "UITableViewReloadDataAnimationKey")
// Update your data source here
self.tableView.reloadData()

CATransition的参考

斯威夫特 5:

let transition = CATransition()
transition.type = CATransitionType.push
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
transition.fillMode = CAMediaTimingFillMode.forwards
transition.duration = 0.5
transition.subtype = CATransitionSubtype.fromTop
self.tableView.layer.add(transition, forKey: "UITableViewReloadDataAnimationKey")
// Update your data source here
self.tableView.reloadData()
于 2013-03-10T22:03:13.147 回答
61

我相信你可以更新你的数据结构,然后:

[tableView beginUpdates];
[tableView deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES];
[tableView insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES];
[tableView endUpdates];

此外,“withRowAnimation”并不完全是布尔值,而是一种动画样式:

UITableViewRowAnimationFade,
UITableViewRowAnimationRight,
UITableViewRowAnimationLeft,
UITableViewRowAnimationTop,
UITableViewRowAnimationBottom,
UITableViewRowAnimationNone,
UITableViewRowAnimationMiddle
于 2010-04-29T03:53:53.727 回答
26

所有这些答案都假设您使用的 UITableView 只有 1 个部分。

要准确处理您有超过 1 个部分的情况,请使用:

NSRange range = NSMakeRange(0, myTableView.numberOfSections);
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:range];
[myTableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic];

(注意:你应该确保你有超过 0 个部分!)

另一件需要注意的事情是,如果您尝试使用此代码同时更新数据源,您可能会遇到 NSInternalInconsistencyException。如果是这种情况,您可以使用与此类似的逻辑:

int sectionNumber = 0; //Note that your section may be different

int nextIndex = [currentItems count]; //starting index of newly added items

[myTableView beginUpdates];

for (NSObject *item in itemsToAdd) {
    //Add the item to the data source
    [currentItems addObject:item];

    //Add the item to the table view
    NSIndexPath *path = [NSIndexPath indexPathForRow:nextIndex++ inSection:sectionNumber];
    [myTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationAutomatic];
}

[myTableView endUpdates];
于 2012-03-20T02:32:32.313 回答
19

解决这个问题的方法是告诉 tableView 删除和添加行和节

insertRowsAtIndexPaths:withRowAnimation:,
deleteRowsAtIndexPaths:withRowAnimation:,
insertSections:withRowAnimation:
deleteSections:withRowAnimation:

UITableView 的方法。

当您调用这些方法时,表格将对您请求的项目进行动画处理,然后对其自身调用 reloadData,以便您可以在此动画之后更新状态。这部分很重要 - 如果您对所有内容进行动画处理但不更改表的 dataSource 返回的数据,则动画完成后行将再次出现。

因此,您的应用程序流程将是:

[self setTableIsInSecondState:YES];

[myTable deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES]];

只要您的表的 dataSource 方法通过检查[self tableIsInSecondState](或其他方式)返回正确的新部分和行集,这将达到您正在寻找的效果。

于 2009-01-07T17:02:43.200 回答
18

我无法评论最佳答案,但快速实施将是:

self.tableView.reloadSections([0], with: UITableViewRowAnimation.fade)

您可以在 reloadSections 的第一个参数中包含想要更新的任意数量的部分。

文档中提供的其他动画: https ://developer.apple.com/reference/uikit/uitableviewrowanimation

淡入淡出 插入或删除的一行或多行淡入或淡出表格视图。

right 插入的一行或多行从右侧滑入;删除的一行或多行向右滑出。

left 插入的一行或多行从左侧滑入;被删除的一行或多行向左滑出。

top 插入的一行或多行从顶部滑入;被删除的一行或多行滑向顶部。

底部 插入的一行或多行从底部滑入;被删除的一行或多行向底部滑出。

case none 插入或删除的行使用默认动画。

中间 表格视图试图将新旧单元格保持在它们已经或将占用的空间的中心。适用于 iPhone 3.2。

自动 表格视图为您选择合适的动画样式。(在 iOS 5.0 中引入。)

于 2016-08-10T21:24:16.623 回答
15

@dmarnel 的Swift 4版本回答:

tableView.reloadSections(IndexSet(integer: 0), with: .automatic)
于 2018-06-07T10:42:05.753 回答
9

快速实施:

let range = NSMakeRange(0, self.tableView!.numberOfSections())
let indexSet = NSIndexSet(indexesInRange: range)
self.tableView!.reloadSections(indexSet, withRowAnimation: UITableViewRowAnimation.Automatic)
于 2014-08-01T19:51:18.710 回答
8

对于斯威夫特 4

tableView.reloadSections([0], with: UITableView.RowAnimation.fade)
于 2018-12-06T22:06:25.423 回答
2

重新加载所有部分,而不仅仅是一个具有自定义持续时间的部分。

用于设置自定义持续时间的用户duration参数。UIView.animate

UIView.animate(withDuration: 0.4, animations: { [weak self] in
    guard let `self` = self else { return }
    let indexSet = IndexSet(integersIn: 0..<self.tableView.numberOfSections)
    self.tableView.reloadSections(indexSet, with: UITableView.RowAnimation.fade)
})
于 2018-12-20T08:57:26.767 回答
1

就我而言,我想在 tableview 中再添加 10 行(用于“显示更多结果”类型的功能),我执行了以下操作:

  NSInteger tempNumber = self.numberOfRows;
  self.numberOfRows += 10;
  NSMutableArray *arrayOfIndexPaths = [[NSMutableArray alloc] init];
  for (NSInteger i = tempNumber; i < self.numberOfRows; i++) {
    [arrayOfIndexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
  }
  [self.tableView beginUpdates];
  [self.tableView insertRowsAtIndexPaths:arrayOfIndexPaths withRowAnimation:UITableViewRowAnimationTop];
  [self.tableView endUpdates];

在大多数情况下,您通常会使用 tableview 的对象数组的计数来代替“self.numberOfRows”。因此,为了确保此解决方案适合您,“arrayOfIndexPaths”需要是插入行的索引路径的准确数组。如果任何索引路径都存在该行,则代码可能会崩溃,因此您应该对这些索引路径使用“reloadRowsAtIndexPaths:withRowAnimation:”方法以避免崩溃

于 2015-04-17T18:52:02.393 回答
1

如果您想将自己的自定义动画添加到 UITableView 单元格,请使用

[theTableView reloadData];
[theTableView layoutSubviews];
NSArray* visibleViews = [theTableView visibleCells];

获得一组可见单元格。然后将任何自定义动画添加到每个单元格。

查看我发布的这个要点,以获得流畅的自定义单元格动画。 https://gist.github.com/floprr/1b7a58e4a18449d962bd

于 2015-06-23T16:47:27.280 回答
1

在Swift中没有 reloadData() 的动画可以这样完成(从 2.2 版开始):

tableview.beginUpdates()
var indexPathsToDeleteForAnimation: [NSIndexPath] = []
var numOfCellsToRemove = ArrayOfItemsToRemove ?? 0

// Do your work here
while numOfCellsToRemove > 0 {
    // ...or here, if you need to add/remove the same amount of objects to/from somewhere
    indexPathsToDeleteForAnimation.append(NSIndexPath(forRow: selectedCellIndex+numOfCellsToRemove, inSection: 0))
    numOfCellsToRemove -= 1
}
tableview.deleteRowsAtIndexPaths(indexPathsToDeleteForAnimation, withRowAnimation: UITableViewRowAnimation.Right)
tableview.endUpdates()

如果您需要在动画结束后调用 reloadData(),您可以像这样接受 CATransaction 中的更改:

CATransaction.begin()
CATransaction.setCompletionBlock({() in self.tableview.reloadData() })
tableview.beginUpdates()
var indexPathsToDeleteForAnimation: [NSIndexPath] = []
var numOfCellsToRemove = ArrayOfItemsToRemove.count ?? 0

// Do your work here
while numOfCellsToRemove > 0 {
     // ...or here, if you need to add/remove the same amount of objects to/from somewhere
     indexPathsToDeleteForAnimation.append(NSIndexPath(forRow: selectedCellIndex+numOfCellsToRemove, inSection: 0))
     numOfCellsToRemove -= 1
}
tableview.deleteRowsAtIndexPaths(indexPathsToDeleteForAnimation, withRowAnimation: UITableViewRowAnimation.Right)
tableview.endUpdates()
CATransaction.commit()

删除行的情况下显示了逻辑,但同样的想法也适用于添加行。您还可以将动画更改为 UITableViewRowAnimation.Left 以使其整洁,或从其他可用动画列表中进行选择。

于 2016-05-25T17:30:44.093 回答
1
CATransition *animation = [CATransition animation];
animation.duration = .3;
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromLeft];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[animation setDuration:.3];

[[_elementTableView layer] addAnimation:animation forKey:@"UITableViewReloadDataAnimationKey"];

[tableView reloadData];
于 2015-11-04T07:49:53.600 回答
1

UITableView 有一个名为“indexPathsForVisibleRows”的字段,您可以使用“reloadItemsAtIndexPaths”方法为可见行设置动画。

    guard let indexPaths = tableView.indexPathsForVisibleRows
    else { return }
    
    self.tableView.layoutIfNeeded()
    self.tableView.reloadItemsAtIndexPaths(indexPaths, animationStyle: .automatic)
于 2020-11-12T23:03:47.233 回答
-1

Swift 中的原生UITableView动画

一次插入和删除所有行,tableView.performBatchUpdates以便它们同时发生。基于@iKenndac 的答案,使用以下方法:

  • tableView.insertSections
  • tableView.insertRows
  • tableView.deleteSections
  • tableView.deleteRows

前任:

 tableView.performBatchUpdates({
   tableView.insertSections([0], with: .top)
 })

这会在零位置插入一个部分,其中包含从顶部加载的动画。这将重新运行该cellForRowAt方法并检查该位置的新单元格。您可以使用特定动画以这种方式重新加载整个表格视图。

回复:OP 问题,需要一个条件标志来显示备用表格视图状态的单元格。

于 2020-05-28T23:42:41.483 回答