更改时为UITableView动画设置reloadData

时间:2009-01-07 07:25:26

标签: cocoa-touch animation

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

这是我尝试过的代码,但它没有做任何事情:

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

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

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

17 个答案:

答案 0 :(得分:388)

实际上,这很简单:

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

来自the documentation

  

调用此方法会导致表视图询问其数据源   指定部分的新单元格。表格视图动画了   插入新细胞,因为它为旧细胞提供动画。

答案 1 :(得分:236)

您可能想要使用:

<强>目标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);

Swift 3

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

答案 2 :(得分:66)

使用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的参考

答案 3 :(得分:59)

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

[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

答案 4 :(得分:23)

所有这些答案都假设您使用的UITableView只有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];

答案 5 :(得分:17)

解决这个问题的方法是告诉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](或其他)返回正确的新的部分和行集,这将达到您正在寻找的效果。

答案 6 :(得分:16)

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

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

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

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

<强>褪色 插入或删除的一行或多行淡入或淡出表视图。

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

<强>左 插入的一行或多行从左侧滑入;删除的一行或多行向左滑动。

热门 插入的一行或多行从顶部滑入;删除的一行或多行向上滑动。

<强>底 插入的一行或多行从底部滑入;删除的一行或多行向下滑动。

案例无 插入或删除的行使用默认动画。

<强>中间 表视图尝试将旧单元和新单元保持在它们所占用或将占用的空间中心。适用于iPhone 3.2。

<强>自动 表视图为您选择适当的动画样式。 (在iOS 5.0中引入。)

答案 7 :(得分:10)

@dmarnel的

Swift 4 版本答案:

tableView.reloadSections(IndexSet(integer: 0), with: .automatic)

答案 8 :(得分:9)

快速实施:

let range = NSMakeRange(0, self.tableView!.numberOfSections())
let indexSet = NSIndexSet(indexesInRange: range)
self.tableView!.reloadSections(indexSet, withRowAnimation: UITableViewRowAnimation.Automatic)

答案 9 :(得分:5)

对于 Swift 4

tableView.reloadSections([0], with: UITableView.RowAnimation.fade)

答案 10 :(得分:1)

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

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

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

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

答案 11 :(得分:1)

重新加载所有部分,而不仅仅是具有自定义时长的部分。

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)
})

答案 12 :(得分: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以使其整洁,或从其他可用动画列表中进行选择。

答案 13 :(得分: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];

答案 14 :(得分: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:”以避免崩溃

答案 15 :(得分:0)

Swift中的本机UITableView动画

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

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

例如:

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

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

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

答案 16 :(得分:0)

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

    guard let indexPaths = tableView.indexPathsForVisibleRows
    else { return }
    
    self.tableView.layoutIfNeeded()
    self.tableView.reloadItemsAtIndexPaths(indexPaths, animationStyle: .automatic)