有一个UITableView的reloadData动画时改变

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

下面是我尝试过的代码,但它什么都不做:

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


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

我该怎么做呢?

158543 次浏览

的方法是告诉tableView删除和添加行和节

< p > insertRowsAtIndexPaths:withRowAnimation:, < br > deleteRowsAtIndexPaths:withRowAnimation:, < br > insertSections:withRowAnimation:和< br > deleteSections:withRowAnimation: < / p >

UITableView的方法。

当你调用这些方法时,表格会动画地输入/输出你所请求的项,然后调用自身的reloadData,这样你就可以在这个动画之后更新状态。这部分很重要——如果您用动画删除了所有内容,但不改变表的dataSource返回的数据,那么这些行将在动画完成后再次出现。

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

[self setTableIsInSecondState:YES];

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

只要你的表的dataSource方法通过检查[self tableIsInSecondState](或任何东西)返回正确的新节和行集,这将达到你想要的效果。

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

[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

其实很简单:

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

的文档:

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

所有这些答案都假设你使用的UITableView只有一个section。

为了准确地处理有多个部分的情况,请使用:

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

你可能想用:

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

Swift 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

有更多的自由使用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()

参考 cattransition

斯威夫特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()

迅速实现:

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

在我的例子中,我想在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];

在大多数情况下,而不是“自我。numberOfRows",你通常会为tableview使用对象数组的计数。因此,为了确保这个解决方案很好地为您工作,“arrayOfIndexPaths”需要是插入行的索引路径的精确数组。如果存在任何索引路径的行,代码可能会崩溃,因此应该为这些索引路径使用“reloadRowsAtIndexPaths:withRowAnimation:”方法以避免崩溃

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

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

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

查看我发布的平滑自定义单元格动画的要点。 https://gist.github.com/floprr/1b7a58e4a18449d962bd < / p >

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

斯威夫特中不使用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。向左使它整洁,或从其他可用的动画列表中选择。

我不能评论上面的答案,但一个快速的实现将是:

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

你可以在reloadSections的第一个参数中包含尽可能多的section。

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

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

< >强吧 插入的一行或行从右侧滑动;

.删除的一行或多行会向右滑动

< >强了 插入的一行或行从左侧滑动;

.

.

.

< >强上 插入的一行或几行从顶部滑动;

.删除的一行或多行向顶部滑动

< >强底 插入的一行或几行从底部滑进;

.删除的一行或多行向底部滑动

< >强情况下没有 插入或删除的行使用默认动画

< >强中间 表视图试图将新旧单元格放在它们曾经或将要占据的空间的中心。

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

斯威夫特4版本的@dmarnel答案:

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

对于斯威夫特4

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

重新加载所有部分,而不仅仅是自定义时间

用户UIView.animateduration参数设置自定义持续时间。

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

本地UITableView动画在Swift

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

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

例:

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

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

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

UITableView有一个名为'indexPathsForVisibleRows'的字段,你可以使用'reloadItemsAtIndexPaths'方法来动画可见行。

guard let indexPathsForVisibleRows = tableView.indexPathsForVisibleRows else {
return
}


tableView.layoutIfNeeded()
tableView.reloadRows(at: indexPathsForVisibleRows, with: .automatic)