我在UITableView中添加或删除行的动画有问题,该行的高度与其他行的高度不同。
以下gifs演示了插入和删除默认高度(44pts)和更大行(100pts)的行的问题。左边的那个是来自模拟器的屏幕录制(最后覆盖第五行的新单元是另一个问题),右边的那个是它应该做什么的模型。
在我的情况下,我有一堆行,每行60磅。当点击单元格中的按钮时,“编辑”单元格将从下方滑出,向下推动下部单元格。此编辑单元格高180磅。当我调用insertRowsAtIndexPaths:withRowAnimation:
或deleteRowsAtIndexPaths:withRowAnimation:
时,动画假定高度为60pts,而不是180pts应该是
这意味着在UITableViewRowAnimationTop
的情况下,新单元格出现在离它最终位置的-60点处,并向下滑动到新位置;它应该做的动画的大约三分之一。与此同时,下面的行从其起始位置平滑地向下移动到180pts,正如它应该的那样。
有没有人为此制定出实际的解决方案?某种方式告诉新行它应该是什么样的动画?
下面是我用来隐藏和显示编辑行的代码。我使用TLSwipeForOptionsCell
来触发编辑,但可以使用例如tableView:didSelectRowAtIndexPath:
轻松复制
-(void)hideEditFields{
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForItem:editFormVisibleForRow+1 inSection:0]] withRowAnimation:UITableViewRowAnimationTop];
editFormVisibleForRow = -1;
[self.tableView endUpdates];
}
-(void)cellDidSelectMore:(TLSwipeForOptionsCell *)cell{
NSIndexPath* indexPath = [self.tableView indexPathForCell:cell];
// do nothing if this is the currently selected row
if(editFormVisibleForRow != indexPath.row){
if(editFormVisibleForRow >= 0){
[self hideEditFields];
// update the index path, as the cell positions (may) have changed
indexPath = [self.tableView indexPathForCell:cell];
}
[self.tableView beginUpdates];
editFormVisibleForRow = indexPath.row;
[self.tableView insertRowsAtIndexPaths:@[
[NSIndexPath indexPathForItem:editFormVisibleForRow+1 inSection:0]
] withRowAnimation:UITableViewRowAnimationTop];
[self.tableView endUpdates];
}
}
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return _dataSource.count + (editFormVisibleForRow >= 0 ? 1 : 0);
}
-(CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
int row = indexPath.row;
if(editFormVisibleForRow >= 0 && row > editFormVisibleForRow && row <= editFormVisibleForRow + 1){
return 180.0f;
}
else return 60.0;
}
稍微调整一下,似乎这是一个常见的问题,没有明确的答案。我在SO上发现的大多数类似问题都没有得到答复,也没有提供特定于提问者情况的解决方法。 (示例:Problem with RowAnimation,Custom UITableViewCell height yields improper animation,UITableView animation glitch when deleting and inserting cells with varying heights)。
此外,我没有尝试制作一个三倍大小的编辑行,而是尝试制作三个较小的行并为其设置动画,但这并不合适,因为它们都是同时出现的。我也尝试过一个接一个地动画它们但是宽松使它看起来很奇怪,发生了明显的3步动画,而不是整个编辑视图在一个动作中滑出视图。
编辑:我刚刚注意到,如果我为我正在尝试设置动画的行上方的行调用reloadRowsAtIndexPaths:withRowAnimation: UITableViewRowAnimationNone
,它会改变动画的行为;即动画假定高度为0pts,如下面的动画所示。它更接近我想要的,但仍然不对,因为动画速度错误并且留下了空隙(在我的应用程序中这意味着背景
颜色戳穿过)
答案 0 :(得分:0)
解决方案非常简单。您需要插入高度为0
的单元格,然后将高度更改为预期大小,然后调用beginUpdates
和endUpdates
。
这是一些伪代码。
var cellHeight: CGFloat = 0
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let dynamicHeightIndex = 2
if indexPath.row == dynamicHeightIndex {
return cellHeight
} else {
return tableView.rowHeight
}
}
func insertCell() {
// First update the data source before inserting the row
tableView.insertRows(at: [someIndexPath], with: .none)
cellHeight = 200
tableView.beginUpdates()
tableView.endUpdates()
}
要删除单元格,您需要等到更新动画完成后再从表格视图中删除。
在iOS 11中,您拥有提供完成功能块的func performBatchUpdates(_:completion:)
。对于以前的版本,您可以尝试使用CATransaction
完成。
cellHeight = 0
CATransaction.begin()
CATransaction.setCompletionBlock({
self.tableView.deleteRows(at: [someIndexPath], with: .none)
})
tableView.beginUpdates()
tableView.endUpdates()
CATransaction.commit()
答案 1 :(得分:-1)
这个,使用didSelectRowAtIndexPath为我工作:
@interface TableController ()
@property (strong,nonatomic) NSArray *theData;
@property (strong,nonatomic) NSIndexPath *pathToEditCell;
@end
@implementation TableController
- (void)viewDidLoad {
[super viewDidLoad];
self.theData = @[@"One",@"Two",@"Three",@"Four",@"Five",@"Six",@"Seven",@"Eight",@"Nine"];
[self.tableView reloadData];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return ([indexPath isEqual:self.pathToEditCell])? 100: 44;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return (self.pathToEditCell == nil)? self.theData.count: self.theData.count + 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if ([indexPath isEqual:self.pathToEditCell]) {
RDEditCell *cell = [tableView dequeueReusableCellWithIdentifier:@"EditCell" forIndexPath:indexPath];
return cell;
}else{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
cell.textLabel.text = self.theData[indexPath.row];
return cell;
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if (self.pathToEditCell == nil) { // first time selecting a row
self.pathToEditCell = [NSIndexPath indexPathForRow:indexPath.row +1 inSection:indexPath.section];
[self.tableView insertRowsAtIndexPaths:@[self.pathToEditCell] withRowAnimation:UITableViewRowAnimationAutomatic];
}else if ([self.pathToEditCell isEqual:indexPath]){ // deletes the edit cell if you click on it
self.pathToEditCell = nil;
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}else{ // close the old edit cell and adds another if you click on another cell while the edit cell is on screen
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:@[self.pathToEditCell] withRowAnimation:UITableViewRowAnimationFade];
self.pathToEditCell = indexPath;
[self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
}
}
对于删除,我喜欢动画的“淡入淡出”选项的外观,但“顶部”也没问题。